前言
本次主要分享一下Java線程的六種狀態及其轉換。
如果對於線程的創建方式不太了解,推薦觀看並發編程——認識java里的線程
線程的狀態及其轉換
操作系統線程的五種狀態
- 新建(NEW)
- 就緒(RUNNABLE)
- 運行(RUNNING)
- 阻塞(BLOCKED)
- 死亡(DEAD)
注意:BLOCKED狀態,包括三種類型狀態:等待(wait)、睡眠(sleep)、阻塞(申請資源:I\O、對象的鎖);
Java線程的六種狀態
- 新建(NEW)
- 可運行(RUNNABLE)
- 阻塞(BLOCKED)
- 等待(WAITING)
- 超時等待(TIMED_WAITING)
- 終止(TERMINATED)
注意:Java線程中的可運行狀態(RUNNABLE)相當於操作系統線程狀態中的就緒狀態(RUNNABLE)和運行狀態(RUNNING)
依據來源於Thread中的源碼中有線程狀態的一個枚舉類,目前只有六種。
Java線程的狀態圖
新建(NEW)
當用new操作符創建一個新線程的時候,如new Thread(r),這個線程還沒有開始運行。這意味着它的狀態就是新建(NEW)。當一個線程處於新建狀態時,程序還沒有開始運行線程中的代碼。
可運行(RUNNABLE)
一旦調用start方法,線程就處於可運行(RUNNABLE)狀態。一個可運行的線程可能正處於運行,也可能沒有運行。要由操作系統為線程提供具體的運行時間。(不過Java規范沒有將正在運行作為一個單獨狀態。一個正在運行的線程仍然處於可運行狀態。)
理解可運行狀態
一旦一個線程開始運行,它不一定始終保持運行。事實上,運行中的線程有時需要暫停,讓其他線程有機會運行。線程調度的細節依賴於操作系統提供的服務。搶占式調度系統給每一個可運行線程一個時間片來執行任務。當時間片用完時,操作系統剝奪該線程的運行權,並給另外一個線程一個機會來運行。當選擇下一個線程時,操作系統會考慮線程的優先級。
現在所有的桌面以及服務器操作系統都使用搶占式調度。但是,像手機這樣的小型設備可能使用協作式調度。在這樣的設備中,一個線程只有在調度yield方法或者被阻塞或等待時才會失去控制權。
在有多個處理器的機器上,每一處理器運行一個線程,可以有多個線程並行運行。當然,如果線程的數目多於處理器數目,調度器還是需要分配時間片。
記住,在任何給定時刻,一個可運行的線程可能正在運行也可能沒有運行(正是因為這樣,這個狀態稱為“可運行”,而不是“運行”)。
阻塞(BLOCKED)
一個正在阻塞等待一個監視器鎖(鎖對象)的線程處於這一狀態,說白了就是一個線程獲取一個內部的對象鎖的時候這個鎖對象被其他線程占用了,那么這個線程就會被阻塞。是一種鎖阻塞。
等待(WAITING)
一個正在無限期等待另一個線程執行一個特別的(喚醒)動作的線程處於這一狀態,例如我們調用Object.wait或者Thread.join這些就會出現這種情況。
超時等待(TIMED_WAITING)
處於這種狀態的線程不會被分配CPU執行時間,不過無須無限期等待被其他線程顯示地喚醒,在達到一定時間后它們會自動喚醒。一般像我們使用sleep(1000)方法,讓線程睡一秒,過一秒之后線程就會自動喚醒繼續執行。
帶有超時參數的方法還有很多,計時版的Object.wait,Thread.join、Lock.tryLock以及Condition.await,調用這些方法會讓線程進入超時等待狀態。
這些后續我會繼續做分享,敬請期待。
終止(TERMINATED)
1、終止狀態為了兩種情況,一種就是我們調用run方法,正常執行完畢,線程自然終止。
2、因為一個沒有捕獲的異常終止了run方法,使線程意外終止。
具體來說,可以調用線程的stop方法殺死線程。該方法拋出一個ThreadDeath錯誤對象,這會殺死線程。不過,stop方法已經被廢除了,不要在你的代碼中調用這個方法。
既然有講到stop方法,那么下一篇就來分享一下線程所提供的一些方法,敬請期待。
感謝諸君的觀看,文中如有紕漏,歡迎在評論區來交流。如果這篇文章幫助到了你,歡迎點贊👍關注。