詳解Java的線程狀態(tài)
Java的每個線程都具有自己的狀態(tài),Thread類中成員變量threadStatus存儲了線程的狀態(tài):
private volatile int threadStatus = 0;
在Thread類中也定義了狀態(tài)的枚舉,共六種,如下:
public enum State {
NEW, // 新建狀態(tài)
RUNNABLE, // 執(zhí)行狀態(tài)
BLOCKED, // 阻塞狀態(tài)
WAITING, // 無限期等待狀態(tài)
TIMED_WAITING, // 有限期等待狀態(tài)
TERMINATED; // 退出狀態(tài)
}threadStatus初始值為0,對應的就是NEW狀態(tài)。
- NEW:新建狀態(tài),new Thread()時處于這個狀態(tài),此時線程還未開始執(zhí)行
- RUNNABLE:執(zhí)行狀態(tài),當調(diào)用了start方法后,線程處于此狀態(tài),當然此刻CPU不一定正在執(zhí)行它
- BLOCKED:阻塞狀態(tài),線程等待鎖時處于此狀態(tài)
- WAITING:無限期等待狀態(tài),需要被喚醒的等待屬于此狀態(tài),如Object.wait
- TIMED_WAITING:有限期等待狀態(tài),調(diào)用一些有超時時間的等待方法會進入此狀態(tài),如Thread.sleep、Object.wait、Thread.join、Lock.tryLock、Condition.await
- TERMINATED:退出狀態(tài),可能是正常運行完畢,也可能是拋出了異常導致線程終止

我們可以通過getState獲取線程的狀態(tài):
State state = thread.getState();
接下來,我們通過示例來感受線程狀態(tài)的變化。
示例一:
Thread t = new Thread(() -> {
System.out.println("sleep");
// 休眠2秒
ThreadUtil.sleep(2000);
System.out.println("run");
});
// 啟動前先打印一下線程狀態(tài)
System.out.println(t.getState());
// 啟動線程
t.start();
// 啟動后立即打印一次線程狀態(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;
當線程內(nèi)執(zhí)行了sleep,休眠2秒鐘,狀態(tài)變更為了TIMED_WAITING;
當線程執(zhí)行完成后,狀態(tài)變更為了TERMINATED。
示例二:
本示例演示在多線程爭搶鎖的情況下,線程狀態(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,進入有限等待狀態(tài)
t2:BLOCKED t2未獲得鎖,因此進入阻塞狀態(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,進入有限等待狀態(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)
示例三:
本示例演示了線程如何進入和退出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()進入無限等待狀態(tài)
t1:WAITING
t1:WAITING
t1:BLOCKED 主線程獲得鎖,進行notify,t1進入了阻塞狀態(tài)
exit t1線程退出同步塊,執(zhí)行完成
t1:TERMINATED t1線程退出
t1:TERMINATED
Java Thread的threadStatus字段值的更新代碼位于hotspot c++源碼中,JDK源碼中看不到。
Java的線程狀態(tài)并非是操作系統(tǒng)的實際線程狀態(tài),但與操作系統(tǒng)的線程狀態(tài)是有對應關系的,后續(xù)有需要深入分析操作系統(tǒng)原理、hotspot源碼再展開。
到此這篇關于詳解Java的線程狀態(tài)的文章就介紹到這了,更多相關Java線程狀態(tài)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot使用Spring-Data-Jpa實現(xiàn)CRUD操作
這篇文章主要為大家詳細介紹了SpringBoot使用Spring-Data-Jpa實現(xiàn)CRUD操作,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-08-08
java使用POI讀取properties文件并寫到Excel的方法
這篇文章主要介紹了java使用POI讀取properties文件并寫到Excel的方法,涉及java操作properties文件及Excel文件的相關技巧,需要的朋友可以參考下2015-06-06
Java開發(fā)之普通web項目轉(zhuǎn)為Maven項目的方法
這篇文章主要給大家介紹了關于Java開發(fā)之普通web項目轉(zhuǎn)為Maven項目的相關資料,文中通過圖文將轉(zhuǎn)換的方法步驟介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2017-12-12

