java中thread的join方法爲什麼能讓線程插隊

在面試中經常會遇到這樣的問題:在主線程中有兩個子線程,如果能讓着兩個子線程能順序的執行?
答案自然是用join來使得兩個線程順序執行,先看一下具體代碼

public class ThreadOfJoin {

    public static void main(String[] args) throws Exception {
        MyThread luck = new MyThread("Luck");
        MyThread timi = new MyThread("Timi");

        luck.start();
        luck.join();
        timi.start();
    }

    @Data
    static class MyThread extends Thread {
        private String userName;
        public MyThread(String userName) {
            this.userName = userName;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println(userName + " - " + i);
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

每個線程啓動後,打印五次信息,通過不同的名字來區分是哪個線程打印的。執行結果如下

Luck - 0
Luck - 1
Luck - 2
Luck - 3
Luck - 4
Timi - 0
Timi - 1
Timi - 2
Timi - 3
Timi - 4

通過結果可以看到join可以使得兩個線程是順序執行,那爲什麼join能控制線程順序執行呢,我們看下join的具體實現

//外部調用的方法
public final void join() throws InterruptedException {
    join(0);
}
//內部的具體實現
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關鍵字來保證線程安全,主線程在調用了luck.start()之後調用了luck.join(),當luck線程未執行完成是,主線程會被以下代碼阻塞

if (millis == 0) {//join()方法默認milis爲0
    while (isAlive()) {//線程未執行完成,此條件爲true
        wait(0);//等待notify
    }
}

當luck線程執行完成之後,此線程的生命週期即將結束,在生命週期結束前,luck線程會使用notifyAll()方法,通知所有正在等待該對象鎖的線程(我即將死去,你們不要再等了)。wait(0)接收到notify之後,會再次進行isAlive()判斷,luck死亡之後,就跳出循環,join方法結束,之後就繼續執行主線程中的其他代碼。

同時我們也能看到join方法裏面能傳遞時間參數,大概作用就是等待指定時間之後,如果之前線程還未執行完成,那麼久不再等待。

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