1. 程式人生 > >Java:執行緒的六種狀態及轉化

Java:執行緒的六種狀態及轉化

目錄

  • Java:執行緒的六種狀態及轉化
    • 一、新建狀態(NEW)
    • 二、執行狀態(RUNNABLE)
      • 就緒狀態(READY)
      • 執行狀態(RUNNING)
    • 三、阻塞狀態(BLOCKED)
    • 四、等待狀態(WAITING)
      • 執行->等待
      • 等待->就緒
    • 五、超時等待狀態(TIMED_WAITING)
      • 執行->超時等待
      • 超時等待->就緒
    • 六、消亡狀態

前文傳送門:多執行緒概述及建立方式

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併發程式設計藝