Java:線程的六種狀態及轉化



前文傳送門: 多線程概述及創建方式

Java:線程的六種狀態及轉化

關於線程的生命周期,網上書上說法不一,難以統一,本篇做一個總結:

java.lang.Thread.State枚舉類中定義了六種線程的狀態,可以調用線程Thread中的getState()方法獲取當前線程的狀態

線程狀態 解釋
NEW 尚未啟動的線程狀態,即線程創建,還未調用start方法
RUNNABLE 就緒狀態(調用start,等待調度)+正在運行
BLOCKED 等待監視器鎖時,陷入阻塞狀態
WAITING 等待狀態的線程正在等待另一線程執行特定的操作(如notify)
TIMED_WAITING 具有指定等待時間的等待狀態
TERMINATED 線程完成執行,終止狀態

下圖源自《Java並發編程藝術》圖4-1

一、新建狀態(NEW)

即用new關鍵字新建一個線程,這個線程就處於新建狀態

二、運行狀態(RUNNABLE)

操作系統中的就緒和運行兩種狀態,在Java中統稱為RUNNABLE。

就緒狀態(READY)

當線程對象調用了start()方法之后,線程處於就緒狀態,就緒意味着該線程可以執行,但具體啥時候執行將取決於JVM里線程調度器的調度。

It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.

  • 不允許對一個線程多次使用start。

  • 線程執行完成之后,不能試圖用start將其喚醒。

其他狀態 ->就緒

  • 線程調用start(),新建狀態轉化為就緒狀態。
  • 線程sleep(long)時間到,等待狀態轉化為就緒狀態。
  • 阻塞式IO操作結果返回,線程變為就緒狀態。
  • 其他線程調用join()方法,結束之后轉化為就緒狀態。
  • 線程對象拿到對象鎖之后,也會進入就緒狀態。

運行狀態(RUNNING)

處於就緒狀態的線程獲得了CPU之后,真正開始執行run()方法的線程執行體時,意味着該線程就已經處於運行狀態。需要注意的是,對於單處理器,一個時刻只能有一個線程處於運行狀態。
對於搶占式策略的系統來說,系統會給每個線程一小段時間處理各自的任務。時間用完之后,系統負責奪回線程占用的資源。下一段時間里,系統會根據一定規則,再次進行調度。

運行狀態轉變為就緒狀態的情形:

  • 線程失去處理器資源。線程不一定完整執行的,執行到一半,說不定就被別的線程搶走了。
  • 調用yield()靜態方法,暫時暫停當前線程,讓系統的線程調度器重新調度一次,它自己完全有可能再次運行。

yield方法的官方解釋:

A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore this hint.

提示調度程序,當前線程願意放棄當前對處理器的使用。這時,當前線程將會被置為就緒狀態,和其他線程一樣等待調度,這時候根據不同優先級決定的概率,當前線程完全有可能再次搶到處理器資源。

三、阻塞狀態(BLOCKED)

阻塞狀態表示線程正等待監視器鎖,而陷入的狀態。

以下場景線程將會阻塞:

  • 線程等待進入synchronized同步方法。
  • 線程等待進入synchronized同步代碼塊。

線程取得鎖,就會從阻塞狀態轉變為就緒狀態。

四、等待狀態(WAITING)

進入該狀態表示當前線程需要等待其他線程做出一些的特定的動作(通知或中斷)。

運行->等待

  • 當前線程運行過程中,其他線程調用join方法,當前線程將會進入等待狀態。
  • 當前線程對象調用wait()方法。
    - LockSupport.park():出於線程調度的目的禁用當前線程

等待->就緒

  • 等待的線程被其他線程對象喚醒notify()notifyAll()
  • LockSupport.unpark(Thread),與上面park方法對應,給出許可證,解除等待狀態

五、超時等待狀態(TIMED_WAITING)

區別於WAITING,它可以在指定的時間自行返回。

運行->超時等待

  • 調用靜態方法,Thread.sleep(long)
  • 線程對象調用wait(long)方法
  • 其他線程調用指定時間的join(long)
  • LockSupport.parkNanos()
  • LockSupport.parkUntil()

補充:
sleep和yield的不同之處:

  • sleep(long)方法會使線程轉入超時等待狀態,時間到了之后才會轉入就緒狀態。而yield()方法不會將線程轉入等待,而是強制線程進入就緒狀態。
  • 使用sleep(long)方法需要處理異常,而yield()不用。

超時等待->就緒

  • 同樣的,等待的線程被其他線程對象喚醒,notify()notifyAll()
  • LockSupport.unpark(Thread)

六、消亡狀態

線程的終止,表示線程已經執行完畢。前面已經說了,已經消亡的線程不能通過start再次喚醒。

  • run()和call()線程執行體中順利執行完畢,線程正常終止
  • 線程拋出一個沒有捕獲的Exception或Error。

需要注意的是:主線成和子線程互不影響,子線程並不會因為主線程結束就結束。


許多地方仍需后期補充,敬請期待。

參考資料:《JAVA並發編程實踐》、《瘋狂Java講義》、《Java並發編程藝術》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM