Java 多線程— 線程的生命週期及方法

這篇博客介紹線程的生命週期。性能優化

線程是一個動態執行的過程,它也有從建立到死亡的過程。網絡

線程的幾種狀態

在 Thread 類中,有一個枚舉內部類:多線程

上面的信息以圖片表示以下:架構

第一張圖:併發

第二張圖:把等待、計時等待、阻塞當作阻塞一個狀態了分佈式

一、新建狀態(new):使用 new 建立一個線程,僅僅只是在堆中分配了內存空間

新建狀態下,線程尚未調用 start()方法啓動,只是存在一個線程對象而已ide

Thread t = new Thread();//這就是t線程的新建狀態微服務

二、可運行狀態(runnable):新建狀態調用 start() 方法,進入可運行狀態。而這個又分紅兩種狀態,ready 和 running,分別表示就緒狀態和運行狀態

就緒狀態:線程對象調用了 start() 方法,等待 JVM 的調度,(此時該線程並無運行)高併發

運行狀態:線程對象得到 JVM 調度,若是存在多個 CPU,那麼運行多個線程並行運行源碼分析

注意:線程對象只能調用一次 start() 方法,不然報錯:illegaThreadStateExecptiong

三、阻塞狀態(blocked):正在運行的線程由於某種緣由放棄 CPU,暫時中止運行,就會進入阻塞狀態。此時 JVM 不會給線程分配 CPU,知道線程從新進入就緒狀態,纔有機會轉到 運行狀態。

注意:阻塞狀態只能先進入就緒狀態,不能直接進入運行狀態

阻塞狀態分爲兩種狀況:

①、當線程 A 處於可運行狀態中,試圖獲取同步鎖時,卻被 B 線程獲取,此時 JVM 把當前 A 線程放入鎖池中,A線程進入阻塞狀態

②、當線程處於運行狀態時,發出了 IO 請求,此時進入阻塞狀態

四、等待狀態(waiting):等待狀態只能被其餘線程喚醒,此時使用的是無參數的 wait() 方法

①、當線程處於運行狀態時,調用了 wait() 方法,此時 JVM 把該線程放入等待池中

五、計時等待(timed waiting):調用了帶參數的 wait(long time)或 sleep(long time) 方法

①、當線程處於運行狀態時,調用了帶參數 wait 方法,此時 JVM 把該線程放入等待池中

②、當前線程調用了 sleep(long time) 方法

六、終止狀態(terminated):一般稱爲死亡狀態,表示線程終止

①、正常終止,執行完 run() 方法,正常結束

②、強制終止,如調用 stop() 方法或 destory() 方法

③、異常終止,執行過程當中發生異常

線程的方法

一、sleep(long millis)

線程休眠:讓執行的線程暫停一段時間,進入計時等待狀態。

static void sleep(long millis):調用此方法後,當前線程放棄 CPU 資源,在指定的時間內,sleep 所在的線程不會得到可運行的機會,此狀態下的線程不會釋放同步鎖。

該方法更多的是用來模擬網絡延遲,讓多線程併發訪問同一資源時的錯誤效果更加明顯。

二、wait()

線程等待:一旦一個線程執行到wait(),就釋放當前的鎖。

注意:此方法必須在同步代碼塊或同步方法中

三、notify()/notifyAll()

喚醒:喚醒wait的一個或全部的線程

    注意:此方法需和wait()成對使用,必須在同步代碼塊或同步方法中

注意 sleep() 和 wait() 的區別,sleep指定時間內當前線程放棄 CPU 資源,線程不會釋放同步鎖,wait 會放棄 CPU 資源,同時也會放棄 同步鎖

四、join()

聯合線程:表示這個線程等待另外一個線程完成後(死亡)才執行,join 方法被調用以後,線程對象處於阻塞狀態。寫在哪一個線程中,哪一個線程阻塞

這種也稱爲聯合線程,就是說把當前線程和當前線程所在的線程聯合成一個線程

五、 yield()

禮讓線程:表示當前線程對象提示調度器本身願意讓出 CPU 資源。

調用該方法後,線程對象進入就緒狀態,因此徹底有可能:某個線程調用了 yield() 方法,可是線程調度器又把它調度出來從新執行。

sleep() 和 yield() 方法的區別:

①、都能使當前處於運行狀態的線程放棄 CPU資源,把運行的機會給其餘線程

②、sleep 方法會給其餘線程運行的機會,可是不考慮其餘線程優先級的問題;yield 方法會優先給更高優先級的線程運行機會

③、調用 sleep 方法後,線程進入計時等待狀態,調用 yield 方法後,線程進入就緒狀態。在此我向你們推薦一個架構學習交流羣。交流學習羣號:821169538  裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多。

join示例:

public class TestThread1 {
    public static void main(String [] args){
        SubThread1 subThread1=new SubThread1();
        subThread1.start();
        for (int i=0;i<=100;i++){ 
           System.out.println(Thread.currentThread().getName()+":"+i);
           if(i==20){
                try {
                    subThread1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class SubThread1 extends Thread{
    @Override
    public void run(){
        for (int i=0;i<=100;i++){
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

運行結果:

main:0
main:1
main:2
main:3
main:4
main:5
main:6
main:7
main:8
main:9
main:10
Thread-0:0
Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
Thread-0:5
Thread-0:6
Thread-0:7
Thread-0:8
Thread-0:9
Thread-0:10
.
.
.
Thread-0:99
Thread-0:100
main:11
main:12
main:13
main:14
main:15
.
.
main:98
main:99
main:100

運行結果分析:在main線程中調用線程A的join()方法,此時main線程中止執行,直至A線程執行完畢,main線程再接着join()以後的代碼執行

 線程的通訊

/**
 * @author: ChenHao
 * @Description:使用兩個線程打印1-100,線程1,線程2交替打印
 * 線程通訊:以下的三個關鍵字使用的話,都得在同步代碼塊或同步方法中。
 * wait():一旦一個線程執行到wait(),就釋放當前的鎖。
 * notify()/notifyAll():喚醒wait的一個或全部的線程
 * 若是不使用break,程序將不會中止
 * @Date: Created in 10:50 2018/10/29
 */
public class TestPrintNum {
    public static void main(String [] args){
        PrintNum printNum=new PrintNum();
        Thread thread1=new Thread(printNum);
        Thread thread2=new Thread(printNum);
        thread1.start();
        thread2.start();
    }
}

class PrintNum implements Runnable{
    int num=1;
    @Override
    public void run(){
        while (true){
            synchronized (this){
                notify();
                if(num<=100){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+num++);
                }else {
                    break;
                }
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

運行結果:

Thread-0:1
Thread-1:2
Thread-0:3
Thread-1:4
Thread-0:5
Thread-1:6
Thread-0:7
Thread-1:8
Thread-0:9
Thread-1:10
.
.
.

運行結果分析:當第一個線程獲取鎖以後,打印後wait,釋放鎖;第二個線程獲取鎖,並喚醒第一個線程,打印後wait;交替打印

相關文章
相關標籤/搜索