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

線程狀態(tài)流程圖
二、完整狀態(tài)轉(zhuǎn)換流程(帶觸發(fā)條件+場(chǎng)景)
線程從創(chuàng)建到終止,會(huì)經(jīng)歷以下核心轉(zhuǎn)換路徑,不同路徑對(duì)應(yīng)不同業(yè)務(wù)場(chǎng)景:
1. 初始啟動(dòng):NEW → RUNNABLE
- 觸發(fā)操作:調(diào)用線程對(duì)象的start()方法(注意:不能重復(fù)調(diào)用,否則拋IllegalThreadStateException)。
- 底層邏輯:start()會(huì)向JVM注冊(cè)線程,JVM向操作系統(tǒng)申請(qǐng)創(chuàng)建線程(如Linux的pthread_create),操作系統(tǒng)將線程加入“就緒隊(duì)列”,等待CPU調(diào)度。
- 場(chǎng)景:
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空閑時(shí),調(diào)度器從就緒隊(duì)列選一個(gè)線程分配時(shí)間片,線程開始執(zhí)行run()方法。 運(yùn)行中→就緒:線程的CPU時(shí)間片用完,或有更高優(yōu)先級(jí)線程進(jìn)入就緒隊(duì)列,當(dāng)前線程被搶占,回到就緒隊(duì)列。
特點(diǎn):此過(guò)程是“隱式轉(zhuǎn)換”,無(wú)需代碼觸發(fā),開發(fā)者無(wú)法通過(guò)Thread.State感知(始終顯示為RUNNABLE)。
3. 鎖競(jìng)爭(zhēng):RUNNABLE ↔ BLOCKED
僅針對(duì)synchronized鎖的競(jìng)爭(zhēng),是“被動(dòng)阻塞”(線程未主動(dòng)放棄,因鎖被占用而暫停)。
RUNNABLE → BLOCKED:
觸發(fā):線程嘗試進(jìn)入synchronized代碼塊/方法,但鎖已被其他線程持有。 邏輯:線程從CPU調(diào)度隊(duì)列退出,進(jìn)入該鎖的“阻塞隊(duì)列”,等待鎖釋放。
BLOCKED → RUNNABLE:
觸發(fā):持有synchronized鎖的線程退出同步塊,釋放鎖。 邏輯:JVM從該鎖的阻塞隊(duì)列中喚醒一個(gè)線程(公平/非公平取決于JVM實(shí)現(xiàn)),線程重新進(jìn)入就緒隊(duì)列,等待CPU調(diào)度。
場(chǎng)景:
Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock) { /* 持有鎖執(zhí)行10秒 */ }
});
Thread t2 = new Thread(() -> {
System.out.println(t2.getState()); // 先 RUNNABLE
synchronized (lock) { /* 競(jìng)爭(zhēng)鎖失敗 */ }
System.out.println(t2.getState()); // 競(jìng)爭(zhēng)時(shí)變?yōu)?BLOCKED
});
t1.start();
Thread.sleep(100); // 確保t1先持有鎖
t2.start();
4. 主動(dòng)等待(無(wú)限):RUNNABLE ↔ WAITING
線程主動(dòng)調(diào)用無(wú)參等待方法,釋放CPU和鎖,必須由其他線程顯式喚醒(否則“卡死”)。
RUNNABLE → WAITING(3種核心觸發(fā)方式):
1.線程持有synchronized鎖時(shí),調(diào)用lock.wait()(必須在同步塊內(nèi),否則拋IllegalMonitorStateException)。 2.調(diào)用另一個(gè)線程的thread.join()(無(wú)參):等待目標(biāo)線程執(zhí)行完畢,若目標(biāo)線程未結(jié)束,當(dāng)前線程進(jìn)入等待。 3.調(diào)用LockSupport.park()(無(wú)參):無(wú)需持有鎖,直接暫停,需通過(guò)LockSupport.unpark(thread)喚醒。
WAITING → RUNNABLE(對(duì)應(yīng)喚醒方式):
1.其他線程調(diào)用lock.notify()/notifyAll()(喚醒后需重新競(jìng)爭(zhēng)鎖,競(jìng)爭(zhēng)成功才回到RUNNABLE)。 2.join()的目標(biāo)線程執(zhí)行完畢(自動(dòng)喚醒)。 3.其他線程調(diào)用LockSupport.unpark(thread)(直接喚醒,無(wú)需競(jìng)爭(zhēng)鎖)。
場(chǎng)景(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. 主動(dòng)等待(計(jì)時(shí)):RUNNABLE ↔ TIMED_WAITING
線程調(diào)用帶超時(shí)參數(shù)的等待方法,釋放資源后等待指定時(shí)間,超時(shí)后自動(dòng)喚醒(也可被提前喚醒)。
RUNNABLE → TIMED_WAITING(5種核心觸發(fā)方式):
1.Thread.sleep(long ms):不釋放鎖,僅暫停指定時(shí)間(最常用,無(wú)需持有鎖)。 2.持有synchronized鎖時(shí),調(diào)用lock.wait(long ms)。 3.調(diào)用thread.join(long ms):等待目標(biāo)線程指定時(shí)間,超時(shí)后不再等。 4.LockSupport.parkNanos(long nanos)/parkUntil(long deadline):帶超時(shí)的暫停。 5.線程池中的線程等待任務(wù)(如ThreadPoolExecutor的awaitTermination(long, TimeUnit))。
TIMED_WAITING → RUNNABLE(2種喚醒方式):
1.等待時(shí)間到期(自動(dòng)喚醒)。 2.被其他線程顯式喚醒(如notify()/unpark(),與WAITING的喚醒邏輯一致)。
場(chǎng)景(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()); // 超時(shí)后回到 RUNNABLE
});
t.start();
Thread.sleep(100);
System.out.println(t.getState()); // 輸出 TIMED_WAITING
6. 最終終止:RUNNABLE → TERMINATED
線程生命周期的終點(diǎn),一旦進(jìn)入此狀態(tài),無(wú)法再回到其他狀態(tài)。
觸發(fā)條件:
1.線程的run()方法正常執(zhí)行完畢(無(wú)異常)。 2.線程在run()方法中拋出未捕獲的異常(如NullPointerException),導(dǎo)致線程崩潰。 3.其他線程調(diào)用thread.stop()(已廢棄,會(huì)強(qiáng)制終止線程,可能導(dǎo)致資源泄漏)。
場(chǎng)景:
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是“被動(dòng)等鎖”(僅因synchronized鎖競(jìng)爭(zhēng)),不釋放已持有的鎖; WAITING/TIMED_WAITING是“主動(dòng)等待”,會(huì)釋放已持有的鎖(sleep()除外,不釋放鎖)。
2.喚醒后的鎖競(jìng)爭(zhēng):
由wait()喚醒的線程,必須重新競(jìng)爭(zhēng)synchronized鎖,競(jìng)爭(zhēng)成功才會(huì)從WAITING/TIMED_WAITING進(jìn)入RUNNABLE,否則會(huì)進(jìn)入BLOCKED狀態(tài)。
3.中斷(interrupt())的影響:
若線程處于WAITING/TIMED_WAITING狀態(tài)時(shí)被中斷(其他線程調(diào)用thread.interrupt()),會(huì)拋出InterruptedException,并清除中斷標(biāo)志,線程從等待狀態(tài)回到RUNNABLE(需處理異常)。 BLOCKED狀態(tài)的線程被中斷,不會(huì)拋出異常,僅設(shè)置中斷標(biāo)志,狀態(tài)仍為BLOCKED。
通過(guò)以上流程,可清晰理解線程在不同場(chǎng)景下的狀態(tài)變化,以及代碼操作對(duì)狀態(tài)的影響。
以上就是Java線程狀態(tài)轉(zhuǎn)換的詳細(xì)過(guò)程的詳細(xì)內(nèi)容,更多關(guān)于Java線程狀態(tài)轉(zhuǎn)換的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot所管理的依賴和需要的依賴沖突問(wèn)題及解決
這篇文章主要介紹了SpringBoot所管理的依賴和需要的依賴沖突問(wèn)題及解決過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2026-05-05
解決SpringBoot請(qǐng)求返回字符串中文亂碼的問(wèn)題
這篇文章主要介紹了解決SpringBoot請(qǐng)求返回字符串中文亂碼的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
SpringBoot處理跨域請(qǐng)求(CORS)的五種方式
跨域資源共享(CORS)是現(xiàn)代Web開發(fā)中常見的問(wèn)題,Spring?Boot提供了多種方式來(lái)處理CORS請(qǐng)求,下面我將詳細(xì)介紹各種實(shí)現(xiàn)方式及其適用場(chǎng)景,需要的朋友可以參考下2025-04-04
Netty分布式NioEventLoop優(yōu)化selector源碼解析
這篇文章主要介紹了Netty分布式NioEventLoop優(yōu)化selector源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
Java項(xiàng)目實(shí)現(xiàn)定時(shí)任務(wù)的三種方法
Java開發(fā)過(guò)程中經(jīng)常會(huì)遇到使用定時(shí)任務(wù)的情況,比如在某個(gè)活動(dòng)結(jié)束時(shí),自動(dòng)生成獲獎(jiǎng)名單,導(dǎo)出excel等,下面這篇文章主要給大家介紹了關(guān)于Java項(xiàng)目實(shí)現(xiàn)定時(shí)任務(wù)的三種方法,需要的朋友可以參考下2022-06-06
Java實(shí)現(xiàn)的基于socket通信的實(shí)例代碼
Java實(shí)現(xiàn)的基于socket通信的實(shí)例代碼,需要的朋友可以參考一下2013-03-03
springBoot?之spring.factories擴(kuò)展機(jī)制示例解析
這篇文章主要為大家介紹了springBoot?之spring.factories擴(kuò)展機(jī)制示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
springboot整合liteflow的實(shí)現(xiàn)示例
本文主要介紹了在Spring Boot項(xiàng)目中整合Liteflow規(guī)則引擎,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-12-12

