詳解Java的線程狀態(tài)
Java的每個(gè)線程都具有自己的狀態(tài),Thread類中成員變量threadStatus存儲(chǔ)了線程的狀態(tài):
private volatile int threadStatus = 0;
在Thread類中也定義了狀態(tài)的枚舉,共六種,如下:
public enum State { NEW, // 新建狀態(tài) RUNNABLE, // 執(zhí)行狀態(tài) BLOCKED, // 阻塞狀態(tài) WAITING, // 無(wú)限期等待狀態(tài) TIMED_WAITING, // 有限期等待狀態(tài) TERMINATED; // 退出狀態(tài) }
threadStatus初始值為0,對(duì)應(yīng)的就是NEW狀態(tài)。
- NEW:新建狀態(tài),new Thread()時(shí)處于這個(gè)狀態(tài),此時(shí)線程還未開(kāi)始執(zhí)行
- RUNNABLE:執(zhí)行狀態(tài),當(dāng)調(diào)用了start方法后,線程處于此狀態(tài),當(dāng)然此刻CPU不一定正在執(zhí)行它
- BLOCKED:阻塞狀態(tài),線程等待鎖時(shí)處于此狀態(tài)
- WAITING:無(wú)限期等待狀態(tài),需要被喚醒的等待屬于此狀態(tài),如Object.wait
- TIMED_WAITING:有限期等待狀態(tài),調(diào)用一些有超時(shí)時(shí)間的等待方法會(huì)進(jìn)入此狀態(tài),如Thread.sleep、Object.wait、Thread.join、Lock.tryLock、Condition.await
- TERMINATED:退出狀態(tài),可能是正常運(yùn)行完畢,也可能是拋出了異常導(dǎo)致線程終止
我們可以通過(guò)getState獲取線程的狀態(tài):
State state = thread.getState();
接下來(lái),我們通過(guò)示例來(lái)感受線程狀態(tài)的變化。
示例一:
Thread t = new Thread(() -> { System.out.println("sleep"); // 休眠2秒 ThreadUtil.sleep(2000); System.out.println("run"); }); // 啟動(dòng)前先打印一下線程狀態(tài) System.out.println(t.getState()); // 啟動(dòng)線程 t.start(); // 啟動(dòng)后立即打印一次線程狀態(tài) System.out.println(t.getState()); // 每隔500毫秒打印一次線程狀態(tài) while (true) { ThreadUtil.sleep(500); System.out.println(t.getState()); }
輸出:
NEW
RUNNABLE
sleep
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
run
TERMINATED
TERMINATED
TERMINATED
TERMINATED
TERMINATED
TERMINATED
TERMINATED
可以看出,線程創(chuàng)建后,初始狀態(tài)為NEW;
調(diào)用start方法后狀態(tài)變更為了RUNNABLE;
當(dāng)線程內(nèi)執(zhí)行了sleep,休眠2秒鐘,狀態(tài)變更為了TIMED_WAITING;
當(dāng)線程執(zhí)行完成后,狀態(tài)變更為了TERMINATED。
示例二:
本示例演示在多線程爭(zhēng)搶鎖的情況下,線程狀態(tài)的變化。
private static Object lock = new Object(); public static void main(String[] args) { Runnable runnable = () -> { // 加鎖 synchronized (lock) { System.out.println(Thread.currentThread().getName() + " lock"); ThreadUtil.sleep(2000); } System.out.println(Thread.currentThread().getName() + " exit"); }; Thread t1 = new Thread(runnable, "t1"); Thread t2 = new Thread(runnable, "t2"); t1.start(); t2.start(); while (true) { ThreadUtil.sleep(500); System.out.println(t1.getName() + ":" + t1.getState()); System.out.println(t2.getName() + ":" + t2.getState()); } }
輸出:
t1 lock t1獲得了鎖
t1:TIMED_WAITING t1 sleep,進(jìn)入有限等待狀態(tài)
t2:BLOCKED t2未獲得鎖,因此進(jìn)入阻塞狀態(tài)
t1:TIMED_WAITING
t2:BLOCKED
t1:TIMED_WAITING
t2:BLOCKED
t1 exit t1釋放鎖,執(zhí)行完成,退出
t2 lock t2獲得鎖
t1:TERMINATED t1已經(jīng)是退出狀態(tài)
t2:TIMED_WAITING t2 sleep,進(jìn)入有限等待狀態(tài)
t1:TERMINATED
t2:TIMED_WAITING
t1:TERMINATED
t2:TIMED_WAITING
t1:TERMINATED
t2:TIMED_WAITING
t2 exit t2釋放鎖,執(zhí)行完成,退出
t1:TERMINATED t1為退出狀態(tài)
t2:TERMINATED t2為退出狀態(tài)
示例三:
本示例演示了線程如何進(jìn)入和退出WAITING狀態(tài)。
private static Object obj = new Object(); public static void main(String[] args) { Runnable runnable = () -> { synchronized (obj) { try { // 等待 obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("exit"); } }; Thread t1 = new Thread(runnable, "t1"); System.out.println(t1.getName() + ":" + t1.getState()); t1.start(); System.out.println(t1.getName() + ":" + t1.getState()); for (int i = 0; i < 20; i++) { ThreadUtil.sleep(500); if(i == 3) { synchronized (obj) { // 喚醒 obj.notify(); } } System.out.println(t1.getName() + ":" + t1.getState()); } }
輸出:
t1:NEW
t1:RUNNABLE
t1:WAITING 調(diào)用了obj.wait()進(jìn)入無(wú)限等待狀態(tài)
t1:WAITING
t1:WAITING
t1:BLOCKED 主線程獲得鎖,進(jìn)行notify,t1進(jìn)入了阻塞狀態(tài)
exit t1線程退出同步塊,執(zhí)行完成
t1:TERMINATED t1線程退出
t1:TERMINATED
Java Thread的threadStatus字段值的更新代碼位于hotspot c++源碼中,JDK源碼中看不到。
Java的線程狀態(tài)并非是操作系統(tǒng)的實(shí)際線程狀態(tài),但與操作系統(tǒng)的線程狀態(tài)是有對(duì)應(yīng)關(guān)系的,后續(xù)有需要深入分析操作系統(tǒng)原理、hotspot源碼再展開(kāi)。
到此這篇關(guān)于詳解Java的線程狀態(tài)的文章就介紹到這了,更多相關(guān)Java線程狀態(tài)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot 全局時(shí)間格式化三種方式示例詳解
時(shí)間格式化在項(xiàng)目中使用頻率是非常高的,當(dāng)我們的 API? 接口返回結(jié)果,需要對(duì)其中某一個(gè) date? 字段屬性進(jìn)行特殊的格式化處理,通常會(huì)用到 SimpleDateFormat? 工具處理,這篇文章主要介紹了3 種 Springboot 全局時(shí)間格式化方式,需要的朋友可以參考下2024-01-01mybatis返回map類型數(shù)據(jù)空值字段不顯示的解決方案
這篇文章主要介紹了mybatis返回map類型數(shù)據(jù)空值字段不顯示的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Java volatile關(guān)鍵字原理剖析與實(shí)例講解
volatile是Java提供的一種輕量級(jí)的同步機(jī)制,Java?語(yǔ)言包含兩種內(nèi)在的同步機(jī)制:同步塊(或方法)和?volatile?變量,本文將詳細(xì)為大家總結(jié)Java volatile關(guān)鍵字,通過(guò)詳細(xì)的代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07JAVA中HTTP基本認(rèn)證(Basic Authentication)實(shí)現(xiàn)
HTTP 基本認(rèn)證是一種簡(jiǎn)單的認(rèn)證方法,本文主要介紹了JAVA中HTTP基本認(rèn)證(Basic Authentication),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07swagger注解@ApiModelProperty失效情況的解決
這篇文章主要介紹了swagger注解@ApiModelProperty失效情況的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06如何使用IDEA 搭建 SpringCloud 項(xiàng)目
所謂微服務(wù),就是要把整個(gè)業(yè)務(wù)模塊拆分成多個(gè)各司其職的小模塊,做到單一職責(zé)原則,不會(huì)重復(fù)開(kāi)發(fā)相同的業(yè)務(wù)代碼,實(shí)現(xiàn)真正意義上的高內(nèi)聚、低耦合,這篇文章主要介紹了如何使用IDEA 搭建 SpringCloud 項(xiàng)目,需要的朋友可以參考下2023-11-11Java并發(fā)J.U.C并發(fā)容器類list set queue
這篇文章主要為大家介紹了Java并發(fā),J.U.C并發(fā)容器類list set queue,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Springboot中com.mysql.cj.jdbc.Driver在yml文件中爆紅的原因解讀
這篇文章主要介紹了Springboot中com.mysql.cj.jdbc.Driver在yml文件中爆紅的原因解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05