Java面試精講:一飛老師帶你再看Java線程(五)

本篇來聊下線程合併-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會線程進行收尾工作, 會喚醒該線程對象鎖中阻塞的所有線程.如果想了解更加詳細,可以百度相關內容。


分享到:


相關文章: