前文傳送門: 多線程概述及創建方式
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並發編程藝術》
