Thread類之join方法

最近在看面試題遇到一個問題描述如下:

有線程 T1、T2 和 T3。你如何確保 T2 線程在 T1 之後執行,並且 T3 線程在 T2 之後執行?

剛看到這個問題時我認爲,想讓T1->T2->T3依次執行,那就依次定義這樣三個線程並按這個順序啓動就可以了嘛!

後來想想是我天真了,其實題目的要求應該是"T2在T1結束後開始執行,T3在T2執行結束後開始執行"

依據測試人員的思想,假如三個線程的執行時間爲T3<T2<T1時呢?

再按照我最初的想法,可以三個線程執行順序就亂套了!

仔細研究後發現這個題目的本質是考察Thread類的join方法的........

下面直接上代碼了↓↓↓

public class Test {

    public static void main(String[] args) {
        Thread ta = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("線程A開始執行.....");
                    Thread.sleep(8000);
                    System.out.println("線程A執行結束.....");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread tb = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    ta.join();//等待線程A執行結束
                    System.out.println("線程B開始執行.....");
                    Thread.sleep(4000);
                    System.out.println("線程B執行結束.....");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread tc = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    tb.join();//等待線程B執行結束
                    System.out.println("線程C開始執行.....");
                    Thread.sleep(1000);
                    System.out.println("線程C執行結束.....");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        ta.start();//線程A開始執行
        tb.start();//線程B開始執行
        tc.start();//線程C開始執行
    }
}

執行結果如下:

Thread類中join方法的解析:

    //方法被synchronized,鎖爲this,this就是調用join的對象
    public final synchronized void join(long millis)
            throws InterruptedException {
        //獲取啓動時刻的時間戳
        long base = System.currentTimeMillis();
        //當前時間的初始化
        long now = 0;
        //①參數小於0,非法情況拋出異常
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        //②參數等於0,意爲着無限等待
        if (millis == 0) {
            //判斷當前線程是否狀態,線程若未運行(未啓動/已終止),則沒有必要繼續等待了
            while (isAlive()) {
                wait(0);
            }
        } else {//③參數大於0
            //判斷當前線程是否狀態,線程若未運行(未啓動/已終止),則沒有必要繼續等待了
            while (isAlive()) {
                //計算出還需等待的時間
                long delay = millis - now;
                //若等待的時間小於0,說明等待時間間隔期已滿,結束循環
                if (delay <= 0) {
                    break;
                }
                //執行線程等待
                wait(delay);
                //計算出線程已等待時間
                now = System.currentTimeMillis() - base;
            }
        }
    }

綜合分析上面面試題的案例:

①線程tb中執行了ta.join(),那麼此時的調用線程爲tb,調用對象爲ta.

②對象ta充當了同步鎖,tb線程會進入等待狀態.當ta執行結束後,tb才被喚醒

③同理,線程tc中執行了tb.join(),那麼此時的調用線程爲tc,調用對象爲tb.

④對象tb充當了同步鎖,tc線程會進入等待狀態.當tb執行結束後,tc才被喚醒

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章