線程狀態(tài)
每一個(gè)線程都有自己的局部變量表喧笔、程序計(jì)數(shù)器脸狸,以及生命周期等冶共,線程的生命周期中各個(gè)階段的狀態(tài)包括:
NEW(初始化),
RUNNABLE(可運(yùn)行的)裤园,
BLOCKED(鎖定或阻塞)询筏,
WAITING(等待)破花,
TIMED_WAITING(定時(shí)等待)滋尉,
TERMINATED(結(jié)束)玉控;
在Thread內(nèi)部類java.lang.Thread.State中定義了線程的生命周期中的所有狀態(tài)
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
獲取線程的狀態(tài)方法:java.lang.Thread#getState
public State getState() {
// get current thread state 獲取當(dāng)前線程的線程狀態(tài)
return sun.misc.VM.toThreadState(threadStatus);
}
各個(gè)狀態(tài)詳情介紹:
1. 新建狀態(tài)(new):
? NEW狀態(tài)為使用new創(chuàng)建一個(gè)線程對(duì)象,在堆中分配內(nèi)存空間在調(diào)用start方法之前的線程所處的狀態(tài)狮惜;在此狀態(tài)下奸远,線程還沒啟動(dòng)既棺,只是創(chuàng)建了一個(gè)線程對(duì)象存儲(chǔ)在堆中讽挟;比如:
Thread t = new Thread(); // 此時(shí)t就屬于新建狀態(tài)
? 當(dāng)新建狀態(tài)下的線程對(duì)象調(diào)用了start方法懒叛,該線程對(duì)象就從新建狀態(tài)進(jìn)入可運(yùn)行狀態(tài)(runnable);
? 線程對(duì)象的start方法只能調(diào)用一次耽梅,多次調(diào)用會(huì)發(fā)生IllegalThreadStateException
薛窥;
2. 可運(yùn)行狀態(tài)(runnable):
? 又可以細(xì)分成兩種狀態(tài),ready
和running
眼姐,分別表示就緒狀態(tài)和運(yùn)行狀態(tài)诅迷。將可運(yùn)行狀態(tài)細(xì)分為兩種狀態(tài)是因?yàn)椴淮_定線程是否獲取到CPU時(shí)間片。
? 就緒狀態(tài):線程對(duì)象調(diào)用start方法之后众旗,等待JVM的調(diào)度(此時(shí)該線程并沒有運(yùn)行)罢杉,還未開始運(yùn)行;
? 運(yùn)行狀態(tài):線程對(duì)象已獲得JVM調(diào)度贡歧,處在運(yùn)行中滩租;如果存在多個(gè)CPU,那么允許多個(gè)線程并行運(yùn)行利朵;
3. 阻塞狀態(tài)(blocked):
? 處于運(yùn)行中的線程因?yàn)槟承┰?strong>放棄CPU時(shí)間片律想,暫時(shí)停止運(yùn)行,就會(huì)進(jìn)入阻塞狀態(tài)绍弟;此時(shí)JVM不會(huì)給線程分配CPU時(shí)間片技即,直到線程重新進(jìn)入就緒狀態(tài)(ready),才有可能轉(zhuǎn)到運(yùn)行狀態(tài)樟遣;
? 阻塞狀態(tài)只能先進(jìn)入就緒狀態(tài)而叼,進(jìn)而由操作系統(tǒng)轉(zhuǎn)到運(yùn)行狀態(tài),不能直接進(jìn)入運(yùn)行狀態(tài)豹悬;
? 阻塞狀態(tài)產(chǎn)生的情況:
- 當(dāng)A線程處于運(yùn)行中葵陵,試圖獲取同步鎖時(shí),但同步鎖卻被B線程獲取屿衅,此時(shí)JVM會(huì)把A線程存到共享資源對(duì)象的鎖池中埃难,A線程進(jìn)入阻塞狀態(tài);
- 當(dāng)線程處于運(yùn)行狀態(tài)涤久,發(fā)出了IO請求時(shí)涡尘,該線程會(huì)進(jìn)入阻塞狀態(tài);
4. 等待狀態(tài)(waiting):
? 運(yùn)行中的線程調(diào)用了wait方法(無參數(shù)的wait方法)响迂,然后JVM會(huì)把該線程儲(chǔ)存到共享資源的對(duì)象等待池中考抄,該線程進(jìn)入等待狀態(tài);處于該狀態(tài)中的線程只能被其他線程喚醒(notify)蔗彤;
5. 計(jì)時(shí)等待狀態(tài)(timed waiting):
? 運(yùn)行中的線程調(diào)用了帶參數(shù)的wait方法或者sleep方法川梅,線程進(jìn)入計(jì)時(shí)等待狀態(tài)疯兼。
? 計(jì)時(shí)等待狀態(tài)下的線程不會(huì)釋放同步鎖/同步監(jiān)聽器;
? 計(jì)時(shí)等待狀態(tài)產(chǎn)生的情況:
- 當(dāng)處于運(yùn)行中的線程贫途,調(diào)用了wait(long time)方法吧彪,JVM會(huì)把當(dāng)前線程存在共享資源對(duì)象等待池中,線程進(jìn)入計(jì)時(shí)等待狀態(tài)丢早;
- 當(dāng)前線程執(zhí)行了sleep(long time)方法姨裸,該線程進(jìn)入計(jì)時(shí)等待狀態(tài);
6. 終止?fàn)顟B(tài)(terminated):
? 也可以稱為死亡狀態(tài)怨酝,表示線程終止傀缩,它的生命走到了盡頭;線程一旦終止,就不能再重啟啟動(dòng)农猬,否則會(huì)發(fā)生IllegalThreadStateException赡艰;
? 終止?fàn)顟B(tài)產(chǎn)生的情況:
- 正常執(zhí)行完run方法而退出,壽終正寢斤葱,屬于正常死亡慷垮;
- 線程執(zhí)行遇到異常而退出,線程中斷苦掘,屬于意外死亡换帜;
線程的生命周期狀態(tài)圖:
上圖解讀:
- 一個(gè)線程在其被創(chuàng)建之后它將處于 NEW(新建)狀態(tài),調(diào)用runnable.start()方法后開始運(yùn)行鹤啡,這時(shí)線程將轉(zhuǎn)換為RUNNABLE狀態(tài)惯驼。RUNNABLE共有2種狀態(tài),就緒(READY)和運(yùn)行中(RUNNING)递瑰,當(dāng)線程獲得了 cpu 時(shí)間片(timeslice)后就處于 RUNNING(運(yùn)行) 狀態(tài)祟牲,未獲得就處于READY(就緒)狀態(tài)。
- 在RUNNABLE狀態(tài)抖部,我們可以轉(zhuǎn)換為waiting,time_waiting和blocked三種狀態(tài)说贝。
- 進(jìn)入waiting狀態(tài)可以執(zhí)行wait()等方法,而waiting狀態(tài)轉(zhuǎn)換為running狀態(tài)可以通過notify等方法慎颗。
- 進(jìn)入time_waiting狀態(tài)可以通過sleep(long millis)方法或 wait(long millis)乡恕,返回runnbale狀態(tài)則可以通過notify等方法。
- 當(dāng)線程調(diào)用同步方法時(shí)俯萎,在沒有獲取到鎖的情況下傲宜,線程將會(huì)進(jìn)入到 BLOCKED(阻塞) 狀態(tài)。
- 線程在執(zhí)行完Runnable 的run()方法之后將會(huì)進(jìn)入到 TERMINATED(終止) 狀態(tài)夫啊。
測試線程狀態(tài)代碼
package com.thread.study;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import java.util.Date;
public class TestThreadState {
public static void main(String[] args) throws InterruptedException {
final long ONE_SECONDS = 1000; // 1秒
Thread mark = new Thread(() -> { // --> NEW
synchronized (args) {
try {
blocking(ONE_SECONDS); // --> BLOCKED
args.wait(); // --> WAITING
args.wait(ONE_SECONDS); // --> TIMED_WAITING
} catch (InterruptedException e) {
}
}
},"測試狀態(tài)的線程");
printThreadState(mark);
new Thread(() -> { // 執(zhí)行使 mark 線程啟動(dòng)后進(jìn)入監(jiān)視器鎖定阻塞的線程(等待獲取鎖)
try {
blocking(ONE_SECONDS + 500);
} catch (InterruptedException e) {
}
}).start();
Thread.sleep(ONE_SECONDS / 10);
mark.start(); // 啟動(dòng) mark 線程 --> RUNNABLE
printThreadState(mark); // 打印 mark 線程 start() 后的狀態(tài)
Thread.sleep(ONE_SECONDS / 10);
printThreadState(mark); // 打印 mark 線程 等待獲取 sync 的狀態(tài)
Thread.sleep(ONE_SECONDS * 2 + 500); // 等待 mark 線程 blocking() 執(zhí)行完成后執(zhí)行 wait()
printThreadState(mark); // 打印 mark 線程 wait() 時(shí)的狀態(tài)
synchronized (args) {
args.notify(); // 喚醒 mark 線程
}
Thread.sleep(ONE_SECONDS / 2); // 等待 mark 線程執(zhí)行 wait(long timeout)
printThreadState(mark); // 獲取 mark 線程 wait(long timeout) 時(shí)的狀態(tài)
Thread.sleep(ONE_SECONDS); // 等待 mark 線程執(zhí)行完畢
printThreadState(mark); // 打印已執(zhí)行完成的狀態(tài) --> TERMINATED
}
static synchronized void blocking(long timeout) throws InterruptedException {
Thread.sleep(timeout);
}
static void printThreadState(Thread stateThread) {
System.out.println(stateThread.getName() + DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MS_PATTERN) + "的線程狀態(tài)為" + stateThread.getState());
}
}
打印結(jié)果:
測試狀態(tài)的線程2021-01-29 21:35:07.732的線程狀態(tài)為NEW
測試狀態(tài)的線程2021-01-29 21:35:07.935的線程狀態(tài)為RUNNABLE
測試狀態(tài)的線程2021-01-29 21:35:08.036的線程狀態(tài)為BLOCKED
測試狀態(tài)的線程2021-01-29 21:35:10.536的線程狀態(tài)為WAITING
測試狀態(tài)的線程2021-01-29 21:35:11.037的線程狀態(tài)為TIMED_WAITING
測試狀態(tài)的線程2021-01-29 21:35:12.039的線程狀態(tài)為TERMINATED