面試突擊:說(shuō)一下線(xiàn)程生命周期,以及轉(zhuǎn)換過(guò)程?
作者 | 磊哥
來(lái)源 | Java面試真題解析(ID:aimianshi666)
轉(zhuǎn)載請(qǐng)聯(lián)系授權(quán)(微信ID:GG_Stone)
線(xiàn)程的生命周期指的是線(xiàn)程從創(chuàng)建到銷(xiāo)毀的整個(gè)過(guò)程,通常情況下線(xiàn)程的生命周期有以下 5 種:
- 初始狀態(tài)
- 可運(yùn)行狀態(tài)
- 運(yùn)行狀態(tài)
- 休眠狀態(tài)
- 終止?fàn)顟B(tài)
它們的狀態(tài)轉(zhuǎn)換如下圖所示:
Java 線(xiàn)程生命周期
Java 線(xiàn)程的生命周期和上面說(shuō)的生命周期是不同的,它有以下 6 種狀態(tài):
- NEW(初始化狀態(tài))
- RUNNABLE(可運(yùn)行/運(yùn)行狀態(tài))
- BLOCKED(阻塞狀態(tài))
- WAITING(無(wú)時(shí)限等待狀態(tài))
- TIMED_WAITING(有時(shí)限等待狀態(tài))
- TERMINATED(終止?fàn)顟B(tài))
我們可以在 Thread 的源碼中可以找到這 6 種狀態(tài),如下所示:
當(dāng)然你也可以使用 Java 代碼,來(lái)打印所有的線(xiàn)程狀態(tài),如下代碼所示:
for (Thread.State value : Thread.State.values()) {
System.out.println(value);
}
以上程序的執(zhí)行結(jié)果如下圖所示:
生命周期轉(zhuǎn)換
接下來(lái)我們聊聊 Java 線(xiàn)程生命周期的轉(zhuǎn)換過(guò)程。
1.從 NEW 到 RUNNABLE
我們創(chuàng)建一個(gè)線(xiàn)程的時(shí)候,也就是 new Thread 的時(shí)候,此時(shí)線(xiàn)程是 NEW 狀態(tài),如下代碼所示:
// 創(chuàng)建線(xiàn)程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// ...
}
});
// 獲取線(xiàn)程狀態(tài)
Thread.State state = thread.getState();
System.out.println(state);
以上程序的執(zhí)行結(jié)果如下圖所示:
然而調(diào)用了線(xiàn)程的 start 方法之后,線(xiàn)程的狀態(tài)就從 NEW 變成了 RUNNABLE,如下代碼所示:
// 創(chuàng)建線(xiàn)程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 獲取到當(dāng)前執(zhí)行的線(xiàn)程
Thread currThread = Thread.currentThread();
// 獲取線(xiàn)程狀態(tài)
Thread.State state = currThread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println(state);
}
});
thread.start();
以上程序的執(zhí)行結(jié)果如下圖所示:
2.從 RUNNABLE 到 BLOCKED
當(dāng)線(xiàn)程中的代碼排隊(duì)執(zhí)行 synchronized 時(shí),線(xiàn)程就會(huì)從 RUNNABLE 狀態(tài)變?yōu)?BLOCKED 阻塞狀態(tài),如下代碼所示:
// 創(chuàng)建線(xiàn)程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
// 等待 100 毫秒
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("排隊(duì)使用鎖");
synchronized (ThreadStates.class) {
}
}
});
thread.start();
// 讓主線(xiàn)程先得到鎖
synchronized (ThreadStates.class) {
// 獲取線(xiàn)程狀態(tài)
Thread.State state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("首次獲取線(xiàn)程狀態(tài):" + state);
// 休眠 1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 再次獲取線(xiàn)程狀態(tài)
state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("第二次獲取線(xiàn)程狀態(tài):" + state);
}
以上程序的執(zhí)行結(jié)果如下圖所示:
當(dāng)線(xiàn)程獲取到 synchronized 鎖之后,就會(huì)從 BLOCKED 狀態(tài)轉(zhuǎn)變?yōu)?RUNNABLE
狀態(tài)。
3.從 RUNNABLE 到 WAITTING
線(xiàn)程調(diào)用 wait() 方法之后,就會(huì)從 RUNNABLE 狀態(tài)變?yōu)?WAITING 無(wú)時(shí)限等待狀態(tài),如下所示:
// 創(chuàng)建線(xiàn)程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (this) {
try {
// 線(xiàn)程休眠
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 啟動(dòng)線(xiàn)程
thread.start();
// 獲取線(xiàn)程狀態(tài)
Thread.State state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("首次獲取線(xiàn)程狀態(tài):" + state);
// 休眠 1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 獲取線(xiàn)程狀態(tài)
state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("第二次獲取線(xiàn)程狀態(tài):" + state);
以上程序的執(zhí)行結(jié)果如下圖所示:
當(dāng)調(diào)用了 notify/notifyAll 方法之后,線(xiàn)程會(huì)從 WAITING 狀態(tài)變成 RUNNABLE 狀態(tài),如下代碼所示:
Object lock = new Object();
// 創(chuàng)建線(xiàn)程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
try {
// 線(xiàn)程休眠
lock.wait();
// 獲取當(dāng)前線(xiàn)程狀態(tài)
Thread.State state = Thread.currentThread().getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("獲取線(xiàn)程狀態(tài):" + state);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 啟動(dòng)線(xiàn)程
thread.start();
// 獲取線(xiàn)程狀態(tài)
Thread.State state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("首次獲取線(xiàn)程狀態(tài):" + state);
// 休眠 1s
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 獲取線(xiàn)程狀態(tài)
state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("第二次獲取線(xiàn)程狀態(tài):" + state);
// 喚醒 thread 線(xiàn)程
synchronized (lock) {
lock.notify();
}
以上程序的執(zhí)行結(jié)果如下圖所示:
4.從 RUNNABLE到TIMED_WATTING
當(dāng)調(diào)用帶超時(shí)時(shí)間的等待方法時(shí),如 sleep(xxx),線(xiàn)程會(huì)從 RUNNABLE 狀態(tài)變成 TIMED_WAITING 有時(shí)限狀態(tài),如下代碼所示:
// 創(chuàng)建線(xiàn)程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 啟動(dòng)線(xiàn)程
thread.start();
// 獲取線(xiàn)程狀態(tài)
Thread.State state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("首次獲取線(xiàn)程狀態(tài):" + state);
// 休眠 1s
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 獲取線(xiàn)程狀態(tài)
state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("第二次獲取線(xiàn)程狀態(tài):" + state);
以上程序的執(zhí)行結(jié)果如下圖所示:
當(dāng)超過(guò)了超時(shí)時(shí)間之后,線(xiàn)程就會(huì)從 TIMED_WAITING 狀態(tài)變成 RUNNABLE 狀態(tài),實(shí)現(xiàn)代碼如下:
// 創(chuàng)建線(xiàn)程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
// 獲取當(dāng)前線(xiàn)程狀態(tài)
Thread.State state = Thread.currentThread().getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("獲取線(xiàn)程狀態(tài):" + state);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 啟動(dòng)線(xiàn)程
thread.start();
// 獲取線(xiàn)程狀態(tài)
Thread.State state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("首次獲取線(xiàn)程狀態(tài):" + state);
// 休眠 1s
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 獲取線(xiàn)程狀態(tài)
state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("第二次獲取線(xiàn)程狀態(tài):" + state);
以上程序的執(zhí)行結(jié)果如下圖所示:
5.RUNNABLE 到 TERMINATED
線(xiàn)程執(zhí)行完之后,就會(huì)從 RUNNABLE 狀態(tài)變成 TERMINATED 銷(xiāo)毀狀態(tài),如下代碼所示:
// 創(chuàng)建線(xiàn)程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 獲取當(dāng)前線(xiàn)程狀態(tài)
Thread.State state = Thread.currentThread().getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("獲取線(xiàn)程狀態(tài):" + state);
}
});
// 啟動(dòng)線(xiàn)程
thread.start();
// 等待 100ms,待線(xiàn)程執(zhí)行完
Thread.sleep(100);
// 獲取線(xiàn)程狀態(tài)
Thread.State state = thread.getState();
// 打印線(xiàn)程狀態(tài)
System.out.println("線(xiàn)程狀態(tài):" + state);
以上程序的執(zhí)行結(jié)果如下圖所示:
總結(jié)
Java 中線(xiàn)程的生命周期有 6 種:NEW(初始化狀態(tài))、RUNNABLE(可運(yùn)行/運(yùn)行狀態(tài))、BLOCKED(阻塞狀態(tài))、WAITING(無(wú)時(shí)限等待狀態(tài))、TIMED_WAITING(有時(shí)限等待狀態(tài))、TERMINATED(終止?fàn)顟B(tài))。線(xiàn)程生命周期的轉(zhuǎn)換流程如下圖所示: