我也學習JAVA多線程-join

在工作中,挺少遇到join關鍵字,但很多多線程資料和麪試過程中,初中級開發工程師總會遇到join。
今天一起學習下join。
join的作用:等待指定的時間(當爲0時,一直等待),直到這個線程執行結束。
先看join方法的定義,join是java.lang.Thread的一個普通方法。

package java.lang;

// Thread竟然實現了Runnable接口,之前好像注意到過,但是沒在意。
// 根據構造方法和run()方法可以看出,本質還是執行的Runnable的實現。
public class Thread implements Runnable {
    …
    public final void join() throws InterruptedException {
        join(0);
    }
    …
}

演示代碼

public class ThreadLearnJoin {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "睡覺");
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "起牀");
            }
        }, "sub-thread");
        t.start();

        System.out.println(Thread.currentThread().getName() + "線程join前");
        t.join();
        System.out.println(Thread.currentThread().getName() + "線程join後");
    }
}

執行結果

main線程join前
sub-thread睡覺
sub-thread起牀
main線程join後

源碼分析

繼續分析join(0)的代碼,首先需要注意的是synchronized關鍵字,其次是isAlive()和wait(0)。在演示代碼中,主線程調用名稱爲sub-thread的子線程t的join()方法。
主線程先獲取t對象上的鎖,並且當t爲Alive狀態時,繼續調用t的wait(0)方法。
由於wait()方法是Object的方法,跟子線程t並沒有關係,wait()會釋放t對象上的鎖,並阻塞當前main線程。
這裏也就隱藏了一個點:t線程調用start()後,進入執行狀態,運行run()方法中的代碼,和t對象上的鎖並沒有任何關係。
run方法並沒有進入synchronized的同步區。

public final synchronized void join(long millis) throws InterruptedException {
    …
    if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }
    }
    …
}

參考資料

問題:雖然s.join()被調用的地方是發生在“Father主線程”中,但是s.join()是通過“子線程s”去調用的join()。  
那麼,join()方法中的isAlive()應該是判斷“子線程s”是不是Alive狀態;對應的wait(0)也應該是“讓子線程s”等待纔對。
但如果是這樣的話,s.join()的作用怎麼可能是“讓主線程等待,直到子線程s完成爲止”呢,應該是讓"子線程等待纔對(因爲調用子線程對象s的wait方法嘛)"?  
答案:wait()的作用是讓“當前線程”等待,而這裏的“當前線程”是指當前在CPU上運行的線程。所以,雖然是調用子線程的wait()方法,但是它是通過“主線程”去調用的;
所以,休眠的是主線程,而不是“子線程”!

這個這麼講的不清楚吧?
調用wait()方法 應該是當前線程持有的對象調用wait() 讓線程等,並釋放對象鎖。
在主線程中調用了s.join() join()方法用synchronized修飾了,也就是說當前主線程已經持有了s的鎖 這個調用s這個對象wait()方法 讓主線程等待並釋放s對象鎖。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章