天天看點

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

關于線程的生命周期,網上書上說法不一,難以統一,本篇做一個總結:java.lang.Thread.State

枚舉類中定義了六種線程的狀态,可以調用線程Thread中的getState()方法擷取目前線程的狀态。

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

下圖源自《Java并發程式設計藝術》圖4-1

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

一、建立狀态(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再次喚醒。

繼續閱讀