線程有幾種狀態,狀態之間的流轉是怎樣的?
Java 中的線程有六種狀態,這些狀態定義在 Thread.State 枚舉中。以下是這六種狀態及其之間的流轉關系:
線程的六種狀態
- NEW(新建狀態):
線程在創建后,但還沒有調用 start() 方法時,處于 NEW 狀態。
線程對象被實例化,但還未開始執行。
- RUNNABLE(可運行狀態):
線程調用了 start() 方法后,進入 RUNNABLE 狀態。
線程可能正在執行(CPU 正在執行該線程),也可能是就緒狀態,等待操作系統調度執行。注意:在 Java 中,RUNNABLE 既包括了線程在運行的狀態,也包括了線程準備好可以運行但暫時未被操作系統調度的狀態。
BLOCKED(阻塞狀態):
線程處于 BLOCKED 狀態時,表示它正在等待獲取某個鎖,以便執行接下來的操作。
這種狀態通常發生在多個線程競爭同一資源(如鎖)時。線程在等待獲得鎖時被阻塞,直到鎖可用。
WAITING(等待狀態):
線程調用了 Object.wait()。
線程調用了 Thread.join()(沒有指定超時)。
線程調用了 LockSupport.park()。
線程進入 WAITING 狀態時,表示它正在等待其他線程的某個操作來喚醒它,且沒有設定超時限制。
常見的情況是:
TIMED_WAITING(定時等待狀態):
線程調用了 Thread.sleep(milliseconds)。
線程調用了 Object.wait(milliseconds)。
線程調用了 Thread.join(milliseconds)。
線程調用了 LockSupport.parkNanos() 或 LockSupport.parkUntil()。
線程進入 TIMED_WAITING 狀態時,表示它正在等待某個條件滿足,但等待是有超時限制的。
線程會等待一段時間,超時后會自動被喚醒。
常見的情況是:
TERMINATED(終止狀態):
線程在執行完畢后,進入 TERMINATED 狀態。
線程的生命周期結束,線程對象不能再被啟動。
線程因為正常完成任務,或者由于異常等原因結束時都會進入這個狀態。
狀態之間的流轉
- NEW → RUNNABLE
調用 Thread.start() 方法后,線程從 NEW 狀態變為 RUNNABLE 狀態。
- RUNNABLE → BLOCKED
線程試圖獲取已被其他線程持有的監視器鎖時,會從 RUNNABLE 狀態變為 BLOCKED 狀態。
BLOCKED → RUNNABLE
當線程獲取到所需的監視器鎖時,會從 BLOCKED 狀態變為 RUNNABLE 狀態。
RUNNABLE → WAITING
線程調用 Object.wait(), Thread.join(), LockSupport.park() 等方法后,會從 RUNNABLE 狀態變為 WAITING 狀態。
RUNNABLE → TIMED_WAITING
線程調用 Thread.sleep(long millis), Object.wait(long timeout), Thread.join(long millis), LockSupport.parkNanos(long nanos), LockSupport.parkUntil(long deadline) 等方法后,會從 RUNNABLE 狀態變為 TIMED_WAITING 狀態。
WAITING → RUNNABLE
當等待條件滿足時,例如 Object.notify(), Object.notifyAll(), Thread.interrupt() 等方法被調用后,線程會從 WAITING 狀態變為 RUNNABLE 狀態。
TIMED_WAITING → RUNNABLE
當等待時間到期或等待條件滿足時,線程會從 TIMED_WAITING 狀態變為 RUNNABLE 狀態。
RUNNABLE → TERMINATED
當線程的 run() 方法正常結束或拋出未捕獲的異常時,線程會從 RUNNABLE 狀態變為 TERMINATED 狀態。
圖解
+--------+ start() +-----------+
| NEW | ------------> | RUNNABLE |
+--------+ +-----------+
| |
+---+ +---+
| |
v v
+-----------+ +---------------+
| BLOCKED | | WAITING |
+-----------+ +---------------+
| |
+---+ +---+
| |
v v
+-----------------+
| TIMED_WAITING |
+-----------------+
|
+---+
|
v
+-----------+
| TERMINATED|
+-----------+
總結:
- NEW:線程尚未啟動。
- RUNNABLE:線程正在等待 CPU 調度執行,可能正在運行,也可能等待 CPU 資源。
- BLOCKED:線程正在等待獲取鎖。
- WAITING:線程正在等待其他線程的通知(沒有超時)。
- TIMED_WAITING:線程正在等待某個條件滿足,并且設置了超時。
- TERMINATED:線程已經執行完畢并結束。
WAITING 和 TIMED_WAITING 的區別?
- WAITING 是無條件的等待,線程會一直等待直到被其他線程喚醒。
- TIMED_WAITING 是帶有超時的等待,線程會等待一段時間,超時后自動喚醒。
這兩種狀態的關鍵區別是 是否有超時限制,WAITING 沒有時間限制,而 TIMED_WAITING 是有超時的。
為什么線程沒有RUNNING狀態?
因為它與 RUNNABLE 狀態的概念重合。
具體原因:
- RUNNABLE 狀態包括正在執行和就緒的線程:
在 Java 的線程狀態模型中,RUNNABLE 狀態既包括了線程已經在 CPU 上執行的狀態(實際上正在運行),也包括了線程處于就緒隊列中,等待 CPU 分配時間片的狀態。
線程一旦被操作系統調度執行,它就進入 RUNNABLE 狀態,但這個狀態的定義并不區分是否正在執行。操作系統負責將線程從就緒隊列中調度到實際的執行狀態,并且 Java 并不會對這個過程做細分。
- 線程狀態模型的設計:
Java 線程狀態模型的設計簡化了線程的生命周期管理,沒有單獨為運行中的線程定義一個狀態。RUNNABLE 狀態作為一個集合狀態,能夠涵蓋線程既可能在執行也可能在等待 CPU 資源的場景。
在操作系統中,線程的調度是由操作系統內核進行的,Java 并不直接控制線程的執行時間或如何選擇線程,而是通過 Java 的線程調度器(JVM)委托給操作系統。所以,線程一旦在運行,實際上是 "正在運行" 或 "就緒等待" 都在 RUNNABLE 狀態下進行管理。
JVM 調度與操作系統的區別:
線程的生命周期與操作系統的調度密切相關。在 Java 中,線程進入 RUNNABLE 狀態意味著它已經準備好由操作系統調度,但操作系統可能會把它從 CPU 上切換出去,導致線程不再“運行”。
JVM 不強制區分 運行中 和 就緒中,因為從 JVM 的角度看,線程要么處于 RUNNABLE 狀態,要么因為某種原因(如阻塞、等待等)不再處于運行狀態。