Java-多線程-線程狀態

Java-多線程-線程狀態

1 簡介

Java線程並不是和Linux線程完全對等的,每個Java線程擁有NEW(新建)、RUNNABLE(就緒)、BLOCKED(阻塞)、WAITING(等待)、TIMED WAITING(計時等待)、TERMINATED(終止)。

Java線程調度屬於搶佔式調度,線程競爭CPU時間分片來執行,一個線程運行幾十毫秒中就處於RUNNING狀態,而時間片用完了被剝奪CPU資源又處於READY狀態了,等待下次調度。

2 線程狀態

在這裏插入圖片描述
在這裏插入圖片描述

  1. NEW(新建)
    使用 new Thread(new Runnable) 類或其子類建立一個線程對象後,該線程對象就處於新建狀態。

    此時線程還未執行,一般是在構造方法中做一些初始化工作。

    NEW狀態的線程只能在thread.start()方法之後轉爲RUNNABLE狀態。

  2. RUNNABLE(就緒)
    NEW狀態的線程調用了thread.start()方法之後,該線程就進入RUNNABLE狀態,等待JVM裏線程調度器的調度,此時處於READY就緒狀態。

    當獲得CPU時間片後,線程開始執行,線程處於RUNNING運行狀態。時間片用完後,線程被剝奪運行資格,等待下一次運行,又變爲就緒狀態。也就是說,此狀態下不能保證線程是就緒還是正在運行。

  3. BLOCKED(阻塞)
    RUNNABLE狀態線程申請被其他線程持有的對象鎖,此時就轉爲BLOCKED狀態,此時線程不運行任何代碼且消耗最少的資源,直到線程調度器重新激活運行該線程。

    當其他線程釋放該對象鎖後,如果本線程競爭到了對象鎖,就轉回RUNNABLE狀態。

  4. WAITING(無期限等待)
    如果一個線程A等待另一個線程給與調度器一個條件時,線程A進入WAITING狀態,等待被其他線程notify喚醒。

    如調用Object.waitThread.joinjava.util.concurrent中的Lock或Condition等。

    條件發生後,就轉回RUNNABLE狀態。(如果是wait方法進入的等待狀態,被notify喚醒後進入對象鎖同步隊列重新競爭鎖,競爭到了就進入RUNNABLE狀態,競爭失敗就進入BLOCKED狀態)

  5. TIMED WAITING(計時等待)
    以上方法有一些帶有時間參數的重載方法(如Object.waitThread.joinjava.util.concurrent中的Lock.tryLock、Condition.await),就會進入TIMED WAITING狀態

     條件發生後,就轉回`RUNNABLE`狀態(如果是wait方法進入的等待狀態,被notify喚醒後進入對象鎖同步隊列重新競爭鎖,競爭到了就進入RUNNABLE狀態,競爭失敗就進入BLOCKED狀態)。
    
  6. TERMINATED(終止)
    線程run方法結束或拋出了未捕獲的異常導致結束。

    在一個TERMINATED的線程上調用start()方法會拋出java.lang.IllegalThreadStateException異常。

3 相關方法

  • Thread.sleep(long millis)
    由當前線程調用此方法,調用後進入TIMED_WAITING狀態,但不釋放對象鎖。millis期滿後線程自動喚醒進入RUNNABLE狀態。

  • Thread.yield(),
    由當前線程調用此方法,給CPU提示表示當前線程願意放棄獲取的CPU時間片(調度器可忽略該提示),但不釋放對象鎖。如果成功釋放時間片則該線程由運行狀態變爲就緒狀態,由調度器再次選擇線程進行調度執行。

    • Sleep對比Yield
      主要是使用場景不同。Sleep主要用來指定睡眠時間讓出CPU,並在時間到後再被系統分配CPU資源,進行調度執行;而Yield是用來主動釋放CPU給其他線程執行,但無法精確控制是否釋放。
  • t.join()/t.join(long millis),
    join方法主要用來等待其他線程運行結束,再繼續運行自己的線程代碼。

    當前線程裏調用其它線程t的join方法,當前線程進入WAITING/TIMED_WAITING狀態,當前線程不會釋放已經持有的對象鎖。

    等到線程t執行完畢或者millis時間到,當前線程重新進入RUNNABLE狀態。

  • obj.wait()
    當前線程調用對象的wait()方法,當前線程會釋放該對象鎖,並進入等待隊列等待其他競爭到鎖的線程執行完後喚醒,重新進入等待隊列進行鎖競爭,競爭成功後纔會從wait方法返回。

    注意這個wait方法只會讓該線程釋放當前Object的對象鎖,而不會放棄擁有的其他對象鎖!

  • obj.wait(mills)
    當前線程調用對象的wait()方法,當前線程會釋放該對象鎖,並進入等待隊列等待其他競爭到鎖的線程執行完後喚醒或時間耗盡,重新進入等待隊列進行鎖競爭,競爭成功後纔會從wait方法返回。

    注意這個wait方法只會讓該線程釋放當前Object的對象鎖,而不會放棄擁有的其他對象鎖!

  • obj.notify()
    該方法用來任意喚醒一個在對象鎖的等待集的線程(其實看了源碼會發現不是任意的,而是一個WaitQueue,FIFO)。

  • obj.notifyAll()
    喚醒在此對象Monitor上等待的所有線程。

4 線程優先級

很多操作系統都提供線程優先級的概念,但是由於平臺特性的問題,Java中的線程優先級和不同平臺中系統線程優先級並不匹配,所以Java線程優先級可以僅僅理解爲“建議優先級”,通俗來說就是java.lang.Thread#setPriority(int newPriority)並不一定生效,有可能Java線程的優先級會被系統自行改變。

參考文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章