線程的生命周期
線程包括哪些狀態的問題說專業一點就是線程的生命周期。
不同的編程語言對線程的生命周期封裝是不同的。
Java 中線程的生命周期
Java 語言中線程共有六種狀態。
- NEW(初始化狀態)
- RUNNABLE(可運行 / 運行狀態)
- BLOCKED(阻塞狀態)
- WAITING(無限時等待)
- TIMED_WAITING(有限時等待)
- TERMINATED(終止狀態) 在操作系統層面,Java 線程中的 BLOCKED、WAITING、TIMED_WAITING 是一種狀態(休眠狀態)。即只要 Java 線程處於這三種狀態之一,就永遠沒有 CPU 的使用權。
如圖:
Java 中線程的狀態的轉變
1. NEW 到 RUNNABLE 狀態
Java 剛創建出來的 Thread 對象就是 NEW 狀態,不會被操作系統調度執行。從 NEW 狀態轉變到 RUNNABLE 狀態調用線程對象的 start() 方法就可以了。
2. RUNNABLE 與 BLOCKED 的狀態轉變
- synchronized 修飾的方法、代碼塊同一時刻只允許一個線程執行,其他線程只能等待,等待的線程會從 RUNNABLE 轉變到 BLOCKED 狀態。
- 當等待的線程獲得 synchronized 隱式鎖時,就又會從 BLOCKED 轉變到 RUNNABLE 狀態。
在操作系統層面,線程是會轉變到休眠狀態的,但是在 JVM 層面,Java 線程的狀態不會發生變化,即 Java 線程的狀態會保持 RUNNABLE 狀態。JVM 層面並不關心操作系統調度相關的狀態,因為在 JVM 看來,等待 CPU 使用權(操作系統層面處於可執行狀態)與等待 I/O(操作系統層面處於休眠狀態)沒有區別,都是在等待某個資源,都歸入了 RUNNABLE 狀態。
Java 在調用阻塞式 API 時,線程會阻塞,指的是操作系統線程的狀態,並不是 Java 線程的狀態。
3. RUNNABLE 與 WAITING 的狀態轉變
- 獲得 synchronized 隱式鎖的線程,調用無參數的 Object.wait() 方法,狀態會從 RUNNABLE 轉變到 WAITING;調用 Object.notify()、Object.notifyAll() 方法,線程可能從 WAITING 轉變到 RUNNABLE 狀態。
- 調用無參數的 Thread.join() 方法。join() 是一種線程同步方法,如有一線程對象 Thread t,當調用 t.join() 的時候,執行代碼的線程的狀態會從 RUNNABLE 轉變到 WAITING,等待 thread t 執行完。當線程 t 執行完,等待它的線程會從 WAITING 狀態轉變到 RUNNABLE 狀態。
- 調用 LockSupport.park() 方法,線程的狀態會從 RUNNABLE 轉變到 WAITING;調用 LockSupport.unpark(Thread thread) 可喚醒目標線程,目標線程的狀態又會從 WAITING 轉變為 RUNNABLE 狀態。
4. RUNNABLE 與 TIMED_WAITING 的狀態轉變
- Thread.sleep(long millis)
- Object.wait(long timeout)
- Thread.join(long millis)
- LockSupport.parkNanos(Object blocker, long deadline)
- LockSupport.parkUntil(long deadline)
TIMED_WAITING 和 WAITING 狀態的區別,僅僅是調用的是超時參數的方法。
5. RUNNABLE 到 TERMINATED 狀態
- 線程執行完 run() 方法后,會自動轉變到 TERMINATED 狀態
- 執行 run() 方法時異常拋出,也會導致線程終止
Thread類的 stop() 方法已經不建議使用