新建 (NEW) 還沒有啓動的線程處於此狀態。java
可運行 (RUNNABLE) 在Java虛擬機中執行的線程處於此狀態。編程
一旦調用了start方法,線程就處於可運行狀態。可運行狀態的線程可能正在運行,也可能尚未運行而正在等待 CPU 時間片。(Java規範中並無分爲可運行狀態和正在運行狀態這兩個狀態,而是把它們合爲一個狀態。因此,能夠把一個正在運行中的線程仍然稱其處於可運行狀態。)markdown
阻塞 (BLOCKED) 被阻塞等待監視器鎖定的線程處於此狀態;處於阻塞狀態的線程不會佔用CPU資源。併發
如下狀況會讓線程進入阻塞狀態:ide
①等待獲取鎖spa
等待獲取一個鎖,而該鎖被其它線程持有,則該線程進入阻塞狀態。當其它線程釋放了該鎖,而且線程調度器容許該線程持有該鎖時,該線程退出阻塞狀態。線程
②IO阻塞code
線程發起了一個阻塞式IO後也會進入阻塞狀態。最典型的場景,如等待用戶輸入內容而後繼續執行。orm
無限期等待 (WAITING) 正在等待另外一個線程執行特定動做的線程處於此狀態。對象
處於這種狀態的線程不會被分配 CPU 時間片,須要等待其它線程顯式地喚醒。
如下方法會讓線程進入無限期的等待狀態
限時等待 (TIMED_WAITING) 正在等待另外一個線程執行動做達到指定等待時間的線程處於此狀態。
處於這種狀態的線程也不會被分配CPU 時間片,在必定時間以後會被系統自動喚醒。
如下方法會讓線程進入限期等待狀態:
Thread.sleep(time) 方法 結束:sleep時間結束
Object.wait(time) 方法 結束:wait時間結束,或者Object.notify() / notifyAll()
LockSupport.parkNanos(time)/parkUntil(time) 方法 結束:park時間結束,或者LockSupport.unpark(當前線程)
死亡 (TERMINATED) 已退出的線程處於此狀態。
注意:在有些書籍(如《Java併發編程實戰》中5.4章節)或籠統的稱呼中,就將阻塞、等待和超時等待這三種狀態統稱爲阻塞狀態。
描 述 | 釋放鎖 | cpu | |
---|---|---|---|
等待 | 線程因等待某個條件而進入等待狀態 | 會釋放鎖 | 不會被分配CPU時間片 |
阻塞 | 線程因競爭鎖失敗而進入阻塞狀態 | 未獲取到鎖 | |
睡眠 | 讓出CPU的使用權讓其它線程執行 | 不會釋放鎖 | 讓出CPU的使用權 |
掛起 | |||
yield | 讓出CPU的使用權,進入就緒狀態(runnable) | 讓出CPU的使用權 | |
中斷 | 並不是終止線程,而是給該線程發送一箇中斷通知,讓其自行決定在合適的時間對中斷通知作出響應(響應能夠是終止線程,或者不作出響應)。 | ||
join | 等待調用該方法的線程執行完畢後,線程再往下繼續執行 |
阻塞狀態:等待獲取鎖或者IO阻塞。
等待狀態:因條件的不容許而暫停運行,會釋放鎖。
①sleep來自Thread類,而wait來自Object類。
②sleep不會釋放鎖,而wait會釋放了鎖。
③sleep必須捕獲異常,而wait/notify/notifyAll不須要捕獲異常。
④wait/notify/notifyAll必須在同步方法或同步代碼塊中調用,而sleep沒有這方面的限制。 (緣由見本文末)
線程中斷並不是線程終止,而是要給該線程發一箇中斷信號讓它本身決定如何處理。
其實是設置了線程的中斷標誌位,在線程阻塞的地方(如調用sleep、wait、join等地方)拋出一個異常InterruptedException,而且中斷狀態也將被清除,從新復位爲false,這樣線程就得以退出阻塞的狀態。
/** * 等待喚醒案例:線程中的通訊 * 建立一個顧客線程(消費者):告知老闆要的包子數量,調用 Wait()方法,放棄cpu執行,進入無限等待狀態 * 建立一個老闆線程(生產者):花了5秒作包子,作好以後調用 Notify()方法,喚醒顧客 * <p> * 注意: * 顧客和老闆線程必須使用同步代碼塊包裹,保證等待和喚醒只能有一個在執行; * 同步使用的鎖對象必須保證惟一; * 只有鎖對象才能調用 wait() 和 Notify()方法 * * @Author: iwen大大怪 * @DateTime: 2020/6/15 20:48 */ public class WaitAndNotify { public static void main(String[] args) { // 建立一個鎖對象 Object obj = new Object(); // 建立一個顧客線程 new Thread(){ @Override public void run() { // 保證等待和喚醒只能有一個在執行 synchronized (obj){ System.out.println("告知老闆要的包子數量"); // 調用 Wait()方法,放棄cpu執行,進入無限等待狀態 try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } // 顧客被喚醒 System.out.println("包子已經作好了,能夠吃了"); } } }.start(); // 建立一個顧客線程 new Thread(){ @Override public void run() { // 花了5秒作包子 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } // 保證等待和喚醒只能有一個在執行 synchronized (obj){ System.out.println("老闆花了5秒"); // 調用 Notify()方法,喚醒顧客 obj.notify(); } } }.start(); } } 複製代碼