操作系統線程和Java線程的狀態
一、操作系統線程的狀態
操作系統的線程主要有以下三個狀態
1. 就緒狀態(ready):線程正在等待使用 CPU,經調度程序調用之後進入 running 狀態。
2. 執行狀態(running):線程正在使用 CPU。
3. 等待狀態(waiting): 線程經過等待事件的調用或者正在等待其他資源(如 I/O)。
二、Java中線程的狀態
Java中線程的狀態分爲6種。
1 // Thread.State 源碼 2 public enum State { 3 NEW, 4 RUNNABLE, 5 BLOCKED, 6 WAITING, 7 TIMED_WAITING, 8 TERMINATED; 9 }
1. 初始狀態(New)
當線程對象被創建但尚未啓動時,處於新建狀態
示例代碼如下:
1 private void testStateNew() { 2 Thread thread = new Thread(() -> {}); 3 System.out.println(thread.getState()); // 輸出 NEW 4 }
2. 可運行狀態 (RUNNABLE)
表示當前線程正在運行中。處於 RUNNABLE 狀態的線程在 Java 虛擬機中運行,也有可能在等待 CPU 分配資源。
說明:
1)Java 線程的RUNNABLE狀態其實包括了操作系統線程的就緒(ready)和運行中(running)兩個狀態
2)線程對象創建後,其他線程(比如main線程)調用了該對象的start()方法。該狀態的線程位於可運行線程池中,等待被線程調度選中,獲取CPU的使用權,此時處於就緒狀態(ready)。就緒狀態的線程在獲得CPU時間片後變爲運行中狀態(running)。
3. 阻塞狀態(BLOCKED)
阻塞狀態。處於 BLOCKED 狀態的線程正等待鎖的釋放以進入同步區。
說明:一個線程獲取一個內部的對象鎖的時候這個鎖對象被其他線程佔用了,那麼這個線程就會被阻塞。是一種鎖阻塞。
4. 等待狀態 (WAITING)
進入該狀態的線程需要等待其他線程做出一些特定動作(通知或中斷)。
調用下面這 3 個方法會使線程進入等待狀態:
1)Object.wait():使當前線程處於等待狀態直到另一個線程喚醒它
2)Thread.join():等待線程執行完畢,底層調用的是 Object 的 wait 方法
3)LockSupport.park():除非獲得調用許可,否則禁用當前線程進行線程調度
5. 超時等待(TIMED_WAITING)
超時等待狀態。線程等待一個具體的時間,時間到後會被自動喚醒。
調用如下方法會使線程進入超時等待狀態:
1)Thread.sleep(long millis):使當前線程睡眠指定時間
2)Object.wait(long timeout):線程休眠指定時間,等待期間可以通過notify()/notifyAll()喚醒
3)Thread.join(long millis):等待當前線程最多執行 millis 毫秒,如果 millis 爲 0,則會一直執行
4)LockSupport.parkNanos(long nanos): 除非獲得調用許可,否則禁用當前線程進行線程調度指定時間
5)LockSupport.parkUntil(long deadline):同上,也是禁止線程進行調度指定時間
說明:處於這種狀態的線程也不會被分配CPU執行時間,不過無須等待被其他線程顯式地喚醒,在一定時間之後它們會由操作系統自動喚醒。
6. 終止狀態(TERMINATED)
線程執行完畢或者因爲異常退出而終止時處於該狀態。
說明:
1)終止狀態爲了兩種情況,一種就是我們調用run方法,正常執行完畢,線程自然終止。
2)因爲一個沒有捕獲的異常終止了run方法,使線程意外終止。
3)一旦進入終止狀態,線程將不再擁有運行的資格,也不能再轉換到其他狀態,生命週期結束。
三、Java中線程狀態的轉換
線程狀態轉換圖如下:
1. WAITING 狀態與 RUNNABLE 狀態的轉換
根據上圖我們知道有 3 個方法可以使線程從 RUNNABLE 狀態轉爲 WAITING 狀態。我們主要介紹下Object.wait()和Thread.join()。
1)Object.wait()
調用wait()方法前線程必須持有對象的鎖。
線程調用wait()方法時,會釋放當前的鎖,直到有其他線程調用notify()/notifyAll()方法喚醒等待鎖的線程。
需要注意的是,其他線程調用notify()方法只會喚醒單個等待鎖的線程,如有有多個線程都在等待這個鎖的話不一定會喚醒到之前調用wait()方法的線程。
同樣,調用notifyAll()方法喚醒所有等待鎖的線程之後,也不一定會馬上把時間片分給剛纔放棄鎖的那個線程,具體要看系統的調度。
2)Thread.join()
調用join()方法,會一直等待這個線程執行完畢(轉換爲 TERMINATED 狀態)。
2. TIMED_WAITING 與 RUNNABLE 狀態轉換
TIMED_WAITING 與 WAITING 狀態類似,只是 TIMED_WAITING 狀態等待的時間是指定的。
1)Thread.sleep(long)
使當前線程睡眠指定時間。需要注意這裏的“睡眠”只是暫時使線程停止執行,並不會釋放鎖。時間到後,線程會重新進入 RUNNABLE 狀態。
2)Object.wait(long)
wait(long)方法使線程進入 TIMED_WAITING 狀態。這裏的wait(long)方法與無參方法 wait()相同的地方是,都可以通過其他線程調用notify()或notifyAll()方法來喚醒。
不同的地方是,有參方法wait(long)就算其他線程不來喚醒它,經過指定時間 long 之後它會自動喚醒,擁有去爭奪鎖的資格。
3)Thread.join(long)
join(long)使當前線程執行指定時間,並且使線程進入 TIMED_WAITING 狀態。
參考鏈接:
https://javabetter.cn/thread/thread-state-and-method.html