本篇來聊下線程合併-join:
概念
join字面上解釋是加入/合併/連接的意思, 而api給出的解釋:
/**
* Waits for this thread to die.
*/
在沒有了解join方法功能前,“等當前線程死亡”,這解釋有點蛋疼。這裡先不解釋,看案例:
public class App {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
//睡2s
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("這是子線程..." + Thread.currentThread().getName());
}
}, "t1");
//啟動子線程
t1.start();
//t1.join();
//打印主線程
System.out.println("這是主線程....main");
}
}
運行後結果:在註釋掉 t1.join() 方法時,打印結果
這是主線程....main
這是子線程...t1
如果解開t1.join() 方法註釋時,打印結果
注意:t1.join必須在start調用後執行,否則沒意義
這是子線程...t1
這是主線程....main
問題:2次操作,一個沒有t1.join, 一個有t1.join, 打印的結果是相反的,為何?
答案:
join按照開篇的描述,其他都表示同一個意思,描述問題角度不一樣而已。
合併:將t1線程合併到main線程中
main線程運行到t1.join方法時,會先阻塞,將cpu執行權交給t1,等待t1執行完畢,再獲取CPU執行剩下的功能。居於這點,可以認為將t1線程執行的邏輯加入到main線程中執行,或者說將t1線程合併到main線程中執行。
等死:等待t1線程終止
跟合併解釋一樣,可以這麼認為:main線程等t1線程執行完畢之後再執行。 也即等t1線程終止後再執行:Waits for this thread to die.
常見的api
thread.join(); //表示等待thread線程邏輯執行完畢 。
thread.join(1000); //表示等待thread線程1毫秒, 操作1毫秒,不再等待。
join實現原理
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
分析
上面源碼, join方法是synchronized修飾的方法, 當main線程調用 t1.join()進入join方法後,main線程馬上獲取到t1對象鎖,接著進入到millis ==0這個分支, 執行wait(0) 方法, 當前線程也即主線程立馬掛起, 在不被喚醒前提下, wait(0) 表示無線等待.
疑問
主線程調用wait(0), 已經阻塞了, 當t1線程執行完畢後, 為什麼沒有notify/notifyAll頁面自動醒來,完成後續任務呢?
答案:其實線程執行完畢之後, jvm會線程進行收尾工作, 會喚醒該線程對象鎖中阻塞的所有線程.如果想了解更加詳細,可以百度相關內容。
閱讀更多 叩丁狼教育stef 的文章