雖然關于討論線程join方法的博客已經(jīng)很多了,不過個人感覺挺多都討論得不夠全面,所以我覺得有必要對其進行一個全面的總結(jié)。

  一、作用

  Thread類中的join方法的主要作用就是同步,它可以使得線程之間的并行執(zhí)行變?yōu)榇袌?zhí)行。具體看代碼:

  

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

public class JoinTest {    public static void main(String [] args) throws InterruptedException {
        ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小東");
        t1.start();        /**join的意思是使得放棄當前線程的執(zhí)行,并返回對應的線程,例如下面代碼的意思就是:
         程序在main線程中調(diào)用t1線程的join方法,則main線程放棄cpu控制權(quán),并返回t1線程繼續(xù)執(zhí)行直到線程t1執(zhí)行完畢
         所以結(jié)果是t1線程執(zhí)行完后,才到主線程執(zhí)行,相當于在main線程中同步t1線程,t1執(zhí)行完了,main線程才有執(zhí)行的機會         */        t1.join();
        t2.start();
    }

}class ThreadJoinTest extends Thread{    public ThreadJoinTest(String name){        super(name);
    }
    @Override    public void run(){        for(int i=0;i<1000;i++){
            System.out.println(this.getName() + ":" + i);
        }
    }
}

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

上面程序結(jié)果是先打印完小明線程,在打印小東線程;  

上面注釋也大概說明了join方法的作用:在A線程中調(diào)用了B線程的join()方法時,表示只有當B線程執(zhí)行完畢時,A線程才能繼續(xù)執(zhí)行。注意,這里調(diào)用的join方法是沒有傳參的,join方法其實也可以傳遞一個參數(shù)給它的,具體看下面的簡單例子:

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

public class JoinTest {    public static void main(String [] args) throws InterruptedException {
        ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小東");
        t1.start();        /**join方法可以傳遞參數(shù),join(10)表示main線程會等待t1線程10毫秒,10毫秒過去后,
         * main線程和t1線程之間執(zhí)行順序由串行執(zhí)行變?yōu)槠胀ǖ牟⑿袌?zhí)行         */
        t1.join(10);        t2.start();
    }

}class ThreadJoinTest extends Thread{    public ThreadJoinTest(String name){        super(name);
    }
    @Override    public void run(){        for(int i=0;i<1000;i++){
            System.out.println(this.getName() + ":" + i);
        }
    }
}

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

上面代碼結(jié)果是:程序執(zhí)行前面10毫秒內(nèi)打印的都是小明線程,10毫秒后,小明和小東程序交替打印。

所以,join方法中如果傳入?yún)?shù),則表示這樣的意思:如果A線程中掉用B線程的join(10),則表示A線程會等待B線程執(zhí)行10毫秒,10毫秒過后,A、B線程并行執(zhí)行。需要注意的是,jdk規(guī)定,join(0)的意思不是A線程等待B線程0秒,而是A線程等待B線程無限時間,直到B線程執(zhí)行完畢,即join(0)等價于join()。

  

  二、join與start調(diào)用順序問題

  上面的討論大概知道了join的作用了,那么,入股 join在start前調(diào)用,會出現(xiàn)什么后果呢?先看下面的測試結(jié)果

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

public class JoinTest {    public static void main(String [] args) throws InterruptedException {
        ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小東");        /**join方法可以在start方法前調(diào)用時,并不能起到同步的作用         */
        t1.join();
        t1.start();        //Thread.yield();        t2.start();
    }

}class ThreadJoinTest extends Thread{    public ThreadJoinTest(String name){        super(name);
    }
    @Override    public void run(){        for(int i=0;i<1000;i++){
            System.out.println(this.getName() + ":" + i);
        }
    }
}

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

上面代碼執(zhí)行結(jié)果是:小明和小東線程交替打印。

所以得到以下結(jié)論:join方法必須在線程start方法調(diào)用之后調(diào)用才有意義。這個也很容易理解:如果一個線程都沒有start,那它也就無法同步了。

 

  三、join方法實現(xiàn)原理

  有了上面的例子,我們大概知道join方法的作用了,那么,join方法實現(xiàn)的原理是什么呢?

  其實,join方法是通過調(diào)用線程的wait方法來達到同步的目的的。例如,A線程中調(diào)用了B線程的join方法,則相當于A線程調(diào)用了B線程的wait方法,在調(diào)用了B線程的wait方法后,A線程就會進入阻塞狀態(tài),具體看下面的源碼:

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

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;
            }
        }
    }

大數(shù)據(jù)培訓,云培訓,數(shù)據(jù)挖掘培訓,云計算培訓,高端軟件開發(fā)培訓,項目經(jīng)理培訓

從源碼中可以看到:join方法的原理就是調(diào)用相應線程的wait方法進行等待操作的,例如A線程中調(diào)用了B線程的join方法,則相當于在A線程中調(diào)用了B線程的wait方法,當B線程執(zhí)行完(或者到達等待時間),B線程會自動調(diào)用自身的notifyAll方法喚醒A線程,從而達到同步的目的。

http://www.cnblogs.com/lcplcpjava/p/6896904.html