Java線程的建立與使用

1、繼承於Thread類

1.建立一個繼承於Thread類的子類
2.重寫Thread類的run(),將此線程的執行操做聲明在run()中
3.建立Thread類的子類的對象
4.經過此對象調用start()java

class MyThread extends Thread {
    @Override
    public void run() {
        for(int i = 0; i < 100; i++) {
            if(i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}
public class ThreadTest {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
    }
}

2、Thread的經常使用方法

/**
 * 1.start():啓動當前線程:調用當前線程的run()
 * 2.run():一般須要重寫Thread類的此方法,將建立的線程要執行的操做聲明在此方法中
 * 3.currentThread():靜態方法,返回當前代碼執行的線程
 * 4.getName():獲取當前線程的名字
 * 5.setName():設置當前線程的名字
 * 6.yield():釋放當前cpu的執行權,但仍是有可能被分配到
 * 7.join():在線程a中調用線程b的join();此時線程a就進入阻塞狀態,直到線程b徹底執行完之後,線程a才結束阻塞狀態。
 * 8.stop():強制終止線程
 * 9.sleep(long millitime):讓當前線程睡眠指定的millitime 毫秒。在指定的millitime毫秒時間內,當前線程是阻塞狀態
 * 10.isAlive():判斷當前線程是否活着
 */
class HelloThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

public class ThreadMethodTest {
    public static void main(String[] args) {
        HelloThread hello = new HelloThread();
        hello.setName("線程1");
        hello.start();

        Thread.currentThread().setName("主線程");
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }

            if (i == 20) {
                try {
                    hello.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

3、Thread的調度

調度方法:
1.同優先級線程組成先進先出隊列,使用時間片策略
2.對高優先級,使用優先調度的搶佔式策略
線程優先級:
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5
線程建立時繼承父線程的優先級
低優先級只是得到調度的機率低,並不是必定是高優先級線程以後才被調用安全

4、實現Runnable接口

/**
 * 1.建立一個實現了Runnable接口的類
 * 2.實現類去實現Runnable中的抽象方法:run()
 * 3.建立實現類的對象
 * 4,將此對象做爲參數傳遞到Thread類的構造器中,建立Thread類的對象
 * 5.經過Thread類的對象調用start()
 */
class twThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}
public class ThreadTest1 {
    public static void main(String[] args) {
        twThread tw = new twThread();
        Thread thread1 = new Thread(tw);
        thread1.start();
    }
}

5、線程的生命週期

線程的狀態:
新建:當一個Thread類或其子類的對象被聲明並建立時,新生的線程對象處於新建狀態。
就緒:處於新建狀態的線程被start()後,將進入線程的隊列等待CPU時間片,此時它已具有了運行條件,只是沒有分配到CPU資源。
運行:當就緒的線程被調度並得到CPU資源時,便進入運行狀態,run()方法定義了線程的操做和功能。
阻塞:在某種特殊狀況下,被人爲掛起或執行輸入輸出操做時,讓出CPU並臨時終止本身的執行,進入阻塞狀態。
死亡:線程完成了它的所有工做或線程被提早強制性地終止或出現異常致使結束。多線程

6、線程安全

package com.study.thread;

/**
 *  1.出現重票,線程安全問題
 *  2.緣由:當某個線程操做車票過程當中,還沒有操做完成時,其餘線程進來,也操做車票
 *  3.解決:當一個線程a操做ticket時,其餘線程不能進來,直到a操做完ticket時,線程才能夠開始操做,ticket,這種狀況即便線程a出現了阻塞,也不能被改變
 *  4,在java中經過同步機制,解決線程安全問題
 *  方式一:同步代碼塊
 *
 *  synchronized(同步監視器) {
 *     // 須要被同步的代碼
 *  }
 *說明:1.操做共享數據的代碼,即爲須要被同步的代碼,不能包含代碼多了,也很多
 *     2.共享數據:多個線程共同操做的變量,好比ticket
 *     3.同步監視器:俗稱鎖,任何一個類的對象,均可以充當鎖
 *          要求:多個線程必需要用同一把鎖
 *          補充:在實現Runnable接口建立多線程方式中,咱們能夠考慮使用this充當同步監視器
 *          繼承Thread類建立多線程,慎用this當同步監視器,考慮用當前類充當同步監視器
 *  方式二:同步方法
 *  若是操做共享數據的代碼完整的聲明在一個方法中,咱們不妨將此方法聲明同步的
 *
 *  5.同步的方式:解決了線程安全問題
 *   操做同步代碼時只能有一個線程參與,其餘線程等待,至關於單線程過程,效率低
 */
class Windows implements Runnable {
    private int ticket = 100;
    Object obj = new Object();
    @Override
    public void run() {
        synchronized(obj) {
            while(ticket > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":賣票,票號爲" + ticket);
                ticket--;
            }
        }
    }
}
public class WindowTest {
    public static void main(String[] args) {
        Windows w1 = new Windows();
        Thread t1 = new Thread(w1);
        Thread t2 = new Thread(w1);
        Thread t3 = new Thread(w1);
        t1.start();
        t2.start();
        t3.start();
    }
}

JDK5.0新語法ide

class Window implements Runnable {
    private int ticket = 100;
    // 實例化ReentrantLock
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                // 調用lock
                lock.lock();
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "售票,票號爲:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }finally {
                // 解鎖
                lock.unlock();
            }


        }
    }
}

public class LockTest {
    public static void main(String[] args) {
        Window window = new Window();

        Thread t1 = new Thread(window);
        Thread t2 = new Thread(window);
        Thread t3 = new Thread(window);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

7、線程通訊

package com.study.channel;
/**
 * 線程通訊:兩個線程交替打印1-100數字
 * 涉及到3個方法
 * wait()一旦執行此方法,當前線程進入阻塞狀態,並釋放同步監視器
 * notify():一旦執行此方法,就會喚醒被wait()的一個線程,若是有多個線程被wait,就喚醒優先級高的
 * notifyall()一旦執行此方法,就會喚醒全部wait的線程
 *
 * 說明:
 *      這三個方法必須放到同步代碼塊或同步方法中
 *      這三個方法的調用者必須是同步代碼塊或同步方法中的同步監視器,不然會出現異常
 * sleep() 和 wait()的異同
 * 相同點:一旦執行方法,  均可以使得當前線程進入阻塞狀態
 * 不一樣點:
 *      兩個方法聲明的位置不一樣:Thread類中聲明sleep()方法,Object類中聲明wait()方法
 *      sleep()可在任何場景下調用,wait()必須在同步代碼塊中調用
 *      若是兩個方法都在同步代碼塊中調用,sleep()不會釋放同步監視器,wait()會釋放同步監視器(鎖)
 *
 */
class Number implements Runnable {
    private int number = 100;

    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                notifyAll();
                if (number >= 1) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + number);
                    number--;
                    try {
                        // 使得調用以下wait以下方法的線程進入阻塞狀態
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            }
        }
    }
}

public class CommuncationTest {
    public static void main(String[] args) {
        Number num = new Number();
        Thread t1 = new Thread(num);
        Thread t2 = new Thread(num);
        Thread t3 = new Thread(num);
        t1.setName("線程1");
        t2.setName("線程2");
        t3.setName("線程3");

        t1.start();
        t2.start();
        t3.start();
    }
}

8、實現Callable建立多線程

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 比實現Runnable強大
 * 1.支持返回值
 * 2.支持拋異常
 * 3.泛型
 */

// 1. 建立一個實現Callable的實現類
class NumThread implements Callable {
    // 實現call 方法,將線程要作的操做生命在call方法中
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                sum += i;
            }
        }
        return sum;
    }

}

public class ThreadNew {
    public static void main(String[] args) {
        // 3.建立callable 實現類的對象
        NumThread num = new NumThread();
        // 4.將此Callbale 實現類的對象傳遞到FutureTask構造器中,建立FutureTask對象
        FutureTask futureTask = new FutureTask(num);
        // 5. 將futureTask傳入Thread構造器
        new Thread(futureTask).start();
        try {
            // 6. 獲取到相應返回值
            Object sum = futureTask.get();
            System.out.println("返回值:" + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

9、線程池建立多線程

package com.study.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 使用線程池建立線程
 * 好處:
 * 1.提高響應速度,
 * 2.下降資源消耗(重複利用線程池中的線程,不須要每次都建立)
 * 3。便於點成管理
 *      corePloolSize  核心池的大小
 *      maxinumPloolSize  最大線程數
 *      keepAliveTime 線程沒有任務時,最多保存多長時間終止
 */
class NumberThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <= 100;i++ ) {
            if(i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}
public class ThreadPool {
    public static void main(String[] args) {
        // 1.提供指定線程數量的線程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //2.執行指定的線程操做,須要提供實現Runnable接口或者Callable 接口實現類的對象
        executorService.execute(new NumberThread()); // 適用於Runnable
//        executorService.submit(Callable callable) // 適用於Callable
        //3.關閉鏈接池
        executorService.shutdown();

    }
}
相關文章
相關標籤/搜索