Java線程狀態(tài)轉(zhuǎn)換的詳細(xì)過程
一、先明確:Java的6種線程狀態(tài)(Thread.State)
這是狀態(tài)轉(zhuǎn)換的“基本單元”,所有轉(zhuǎn)換都圍繞這6種狀態(tài)進(jìn)行:
1.NEW(新建):線程對象已創(chuàng)建(如new Thread()),但未調(diào)用start(),JVM未為其分配操作系統(tǒng)級線程資源。 2.RUNNABLE(可運(yùn)行):調(diào)用start()后進(jìn)入此狀態(tài),對應(yīng)操作系統(tǒng)線程的“就緒”和“運(yùn)行中”——線程要么在等待CPU調(diào)度(就緒),要么正在CPU上執(zhí)行run()方法(運(yùn)行中),JVM層面不區(qū)分這兩個子狀態(tài)。 3.BLOCKED(阻塞):僅因競爭synchronized鎖失敗而暫停,等待鎖釋放(不涉及Lock接口的鎖,Lock鎖競爭會進(jìn)入WAITING/TIMED_WAITING)。 4.WAITING(無限等待):線程主動調(diào)用無參等待方法,釋放CPU和持有的鎖,必須依賴其他線程顯式喚醒(否則永久等待)。 5.TIMED_WAITING(計時等待):線程調(diào)用帶超時參數(shù)的等待方法,釋放資源后僅等待指定時間,超時后自動喚醒,也可被提前喚醒。 6.TERMINATED(終止):線程的run()方法執(zhí)行完畢,或因未捕獲異常崩潰,生命周期徹底結(jié)束。

線程狀態(tài)流程圖
二、完整狀態(tài)轉(zhuǎn)換流程(帶觸發(fā)條件+場景)
線程從創(chuàng)建到終止,會經(jīng)歷以下核心轉(zhuǎn)換路徑,不同路徑對應(yīng)不同業(yè)務(wù)場景:
1. 初始啟動:NEW → RUNNABLE
- 觸發(fā)操作:調(diào)用線程對象的start()方法(注意:不能重復(fù)調(diào)用,否則拋IllegalThreadStateException)。
- 底層邏輯:start()會向JVM注冊線程,JVM向操作系統(tǒng)申請創(chuàng)建線程(如Linux的pthread_create),操作系統(tǒng)將線程加入“就緒隊列”,等待CPU調(diào)度。
- 場景:
Thread t = new Thread(() -> { /* 任務(wù)邏輯 */ });
System.out.println(t.getState()); // 輸出 NEW
t.start();
System.out.println(t.getState()); // 輸出 RUNNABLE(大概率,因CPU調(diào)度有延遲)
2. 可運(yùn)行態(tài)內(nèi)部切換:RUNNABLE(就緒)↔ RUNNABLE(運(yùn)行中)
觸發(fā)操作:由操作系統(tǒng)的CPU調(diào)度算法控制,JVM不干預(yù)。
就緒→運(yùn)行中:CPU空閑時,調(diào)度器從就緒隊列選一個線程分配時間片,線程開始執(zhí)行run()方法。 運(yùn)行中→就緒:線程的CPU時間片用完,或有更高優(yōu)先級線程進(jìn)入就緒隊列,當(dāng)前線程被搶占,回到就緒隊列。
特點(diǎn):此過程是“隱式轉(zhuǎn)換”,無需代碼觸發(fā),開發(fā)者無法通過Thread.State感知(始終顯示為RUNNABLE)。
3. 鎖競爭:RUNNABLE ↔ BLOCKED
僅針對synchronized鎖的競爭,是“被動阻塞”(線程未主動放棄,因鎖被占用而暫停)。
RUNNABLE → BLOCKED:
觸發(fā):線程嘗試進(jìn)入synchronized代碼塊/方法,但鎖已被其他線程持有。 邏輯:線程從CPU調(diào)度隊列退出,進(jìn)入該鎖的“阻塞隊列”,等待鎖釋放。
BLOCKED → RUNNABLE:
觸發(fā):持有synchronized鎖的線程退出同步塊,釋放鎖。 邏輯:JVM從該鎖的阻塞隊列中喚醒一個線程(公平/非公平取決于JVM實(shí)現(xiàn)),線程重新進(jìn)入就緒隊列,等待CPU調(diào)度。
場景:
Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock) { /* 持有鎖執(zhí)行10秒 */ }
});
Thread t2 = new Thread(() -> {
System.out.println(t2.getState()); // 先 RUNNABLE
synchronized (lock) { /* 競爭鎖失敗 */ }
System.out.println(t2.getState()); // 競爭時變?yōu)?BLOCKED
});
t1.start();
Thread.sleep(100); // 確保t1先持有鎖
t2.start();
4. 主動等待(無限):RUNNABLE ↔ WAITING
線程主動調(diào)用無參等待方法,釋放CPU和鎖,必須由其他線程顯式喚醒(否則“卡死”)。
RUNNABLE → WAITING(3種核心觸發(fā)方式):
1.線程持有synchronized鎖時,調(diào)用lock.wait()(必須在同步塊內(nèi),否則拋IllegalMonitorStateException)。 2.調(diào)用另一個線程的thread.join()(無參):等待目標(biāo)線程執(zhí)行完畢,若目標(biāo)線程未結(jié)束,當(dāng)前線程進(jìn)入等待。 3.調(diào)用LockSupport.park()(無參):無需持有鎖,直接暫停,需通過LockSupport.unpark(thread)喚醒。
WAITING → RUNNABLE(對應(yīng)喚醒方式):
1.其他線程調(diào)用lock.notify()/notifyAll()(喚醒后需重新競爭鎖,競爭成功才回到RUNNABLE)。 2.join()的目標(biāo)線程執(zhí)行完畢(自動喚醒)。 3.其他線程調(diào)用LockSupport.unpark(thread)(直接喚醒,無需競爭鎖)。
場景(wait/notify):
Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock) {
System.out.println(t1.getState()); // RUNNABLE
lock.wait(); // 釋放鎖,進(jìn)入 WAITING
System.out.println(t1.getState()); // 被喚醒并重新獲鎖后,回到 RUNNABLE
}
});
Thread t2 = new Thread(() -> {
synchronized (lock) {
lock.notify(); // 喚醒t1
}
});
t1.start();
Thread.sleep(100);
System.out.println(t1.getState()); // 輸出 WAITING
t2.start();
5. 主動等待(計時):RUNNABLE ↔ TIMED_WAITING
線程調(diào)用帶超時參數(shù)的等待方法,釋放資源后等待指定時間,超時后自動喚醒(也可被提前喚醒)。
RUNNABLE → TIMED_WAITING(5種核心觸發(fā)方式):
1.Thread.sleep(long ms):不釋放鎖,僅暫停指定時間(最常用,無需持有鎖)。 2.持有synchronized鎖時,調(diào)用lock.wait(long ms)。 3.調(diào)用thread.join(long ms):等待目標(biāo)線程指定時間,超時后不再等。 4.LockSupport.parkNanos(long nanos)/parkUntil(long deadline):帶超時的暫停。 5.線程池中的線程等待任務(wù)(如ThreadPoolExecutor的awaitTermination(long, TimeUnit))。
TIMED_WAITING → RUNNABLE(2種喚醒方式):
1.等待時間到期(自動喚醒)。 2.被其他線程顯式喚醒(如notify()/unpark(),與WAITING的喚醒邏輯一致)。
場景(sleep):
Thread t = new Thread(() -> {
System.out.println(t.getState()); // RUNNABLE
try {
Thread.sleep(1000); // 進(jìn)入 TIMED_WAITING
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(t.getState()); // 超時后回到 RUNNABLE
});
t.start();
Thread.sleep(100);
System.out.println(t.getState()); // 輸出 TIMED_WAITING
6. 最終終止:RUNNABLE → TERMINATED
線程生命周期的終點(diǎn),一旦進(jìn)入此狀態(tài),無法再回到其他狀態(tài)。
觸發(fā)條件:
1.線程的run()方法正常執(zhí)行完畢(無異常)。 2.線程在run()方法中拋出未捕獲的異常(如NullPointerException),導(dǎo)致線程崩潰。 3.其他線程調(diào)用thread.stop()(已廢棄,會強(qiáng)制終止線程,可能導(dǎo)致資源泄漏)。
場景:
Thread t = new Thread(() -> {
// 任務(wù)執(zhí)行1秒后結(jié)束
try { Thread.sleep(1000); } catch (InterruptedException e) {}
});
t.start();
Thread.sleep(2000); // 等待t執(zhí)行完畢
System.out.println(t.getState()); // 輸出 TERMINATED
三、關(guān)鍵注意點(diǎn)
1.BLOCKED vs WAITING/TIMED_WAITING:
BLOCKED是“被動等鎖”(僅因synchronized鎖競爭),不釋放已持有的鎖; WAITING/TIMED_WAITING是“主動等待”,會釋放已持有的鎖(sleep()除外,不釋放鎖)。
2.喚醒后的鎖競爭:
由wait()喚醒的線程,必須重新競爭synchronized鎖,競爭成功才會從WAITING/TIMED_WAITING進(jìn)入RUNNABLE,否則會進(jìn)入BLOCKED狀態(tài)。
3.中斷(interrupt())的影響:
若線程處于WAITING/TIMED_WAITING狀態(tài)時被中斷(其他線程調(diào)用thread.interrupt()),會拋出InterruptedException,并清除中斷標(biāo)志,線程從等待狀態(tài)回到RUNNABLE(需處理異常)。 BLOCKED狀態(tài)的線程被中斷,不會拋出異常,僅設(shè)置中斷標(biāo)志,狀態(tài)仍為BLOCKED。
通過以上流程,可清晰理解線程在不同場景下的狀態(tài)變化,以及代碼操作對狀態(tài)的影響。
以上就是Java線程狀態(tài)轉(zhuǎn)換的詳細(xì)過程的詳細(xì)內(nèi)容,更多關(guān)于Java線程狀態(tài)轉(zhuǎn)換的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot使用Filter實(shí)現(xiàn)簽名認(rèn)證鑒權(quán)的示例代碼
這篇文章主要介紹了SpringBoot使用Filter實(shí)現(xiàn)簽名認(rèn)證鑒權(quán)的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
Springboot mybais配置多數(shù)據(jù)源過程解析
這篇文章主要介紹了Springboot+mybais配置多數(shù)據(jù)源過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03
java使用bitmap實(shí)現(xiàn)可回收自增id的示例
本文主要介紹了java使用bitmap實(shí)現(xiàn)可回收自增id的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-10-10
SpringBoot 整合 JMSTemplate的示例代碼
這篇文章主要介紹了SpringBoot 整合 JMSTemplate的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
idea install 時提示jdk的某個jar包的包不存在的問題
這篇文章主要介紹了idea install 時提示jdk的某個jar包的包不存在的問題,本文給大家分享解決方法,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
java 靜態(tài)工廠代替多參構(gòu)造器的適用情況與優(yōu)劣
這篇文章主要介紹了java 靜態(tài)工廠代替多參構(gòu)造器的優(yōu)劣,幫助大家更好的理解和使用靜態(tài)工廠方法,感興趣的朋友可以了解下2020-12-12

