java 線程方法join的簡單總結

雖然關於討論線程join方法的博客已經不少了,不過我的感受挺多都討論得不夠全面,因此我以爲有必要對其進行一個全面的總結。ide

  1、做用測試

  Thread類中的join方法的主要做用就是同步,它可使得線程之間的並行執行變爲串行執行。具體看代碼:this

  

public class JoinTest {
    public static void main(String [] args) throws InterruptedException {
        ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小東");
        t1.start();
        /**join的意思是使得放棄當前線程的執行,並返回對應的線程,例以下面代碼的意思就是:
         程序在main線程中調用t1線程的join方法,則main線程放棄cpu控制權,並返回t1線程繼續執行直到線程t1執行完畢
         因此結果是t1線程執行完後,纔到主線程執行,至關於在main線程中同步t1線程,t1執行完了,main線程纔有執行的機會
         */
        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);
        }
    }
}

上面程序結果是先打印完小明線程,在打印小東線程;  spa

上面註釋也大概說明了join方法的做用:在A線程中調用了B線程的join()方法時,表示只有當B線程執行完畢時,A線程才能繼續執行。注意,這裏調用的join方法是沒有傳參的,join方法其實也能夠傳遞一個參數給它的,具體看下面的簡單例子:線程

public class JoinTest {
    public static void main(String [] args) throws InterruptedException {
        ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小東");
        t1.start();
        /**join方法能夠傳遞參數,join(10)表示main線程會等待t1線程10毫秒,10毫秒過去後,
         * main線程和t1線程之間執行順序由串行執行變爲普通的並行執行
         */
        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);
        }
    }
}

上面代碼結果是:程序執行前面10毫秒內打印的都是小明線程,10毫秒後,小明和小東程序交替打印。code

因此,join方法中若是傳入參數,則表示這樣的意思:若是A線程中掉用B線程的join(10),則表示A線程會等待B線程執行10毫秒,10毫秒事後,A、B線程並行執行。須要注意的是,jdk規定,join(0)的意思不是A線程等待B線程0秒,而是A線程等待B線程無限時間,直到B線程執行完畢,即join(0)等價於join()。blog

  

  2、join與start調用順序問題get

  上面的討論大概知道了join的做用了,那麼,入股 join在start前調用,會出現什麼後果呢?先看下面的測試結果同步

public class JoinTest {
    public static void main(String [] args) throws InterruptedException {
        ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小東");
        /**join方法能夠在start方法前調用時,並不能起到同步的做用
         */
        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);
        }
    }
}

上面代碼執行結果是:小明和小東線程交替打印。源碼

因此獲得如下結論:join方法必須在線程start方法調用以後調用纔有意義。這個也很容易理解:若是一個線程都沒有start,那它也就沒法同步了。

 

  3、join方法實現原理

  有了上面的例子,咱們大概知道join方法的做用了,那麼,join方法實現的原理是什麼呢?

  其實,join方法是經過調用線程的wait方法來達到同步的目的的。例如,A線程中調用了B線程的join方法,則至關於A線程調用了B線程的wait方法,在調用了B線程的wait方法後,A線程就會進入阻塞狀態,具體看下面的源碼:

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方法的原理就是調用相應線程的wait方法進行等待操做的,例如A線程中調用了B線程的join方法,則至關於在A線程中調用了B線程的wait方法,當B線程執行完(或者到達等待時間),B線程會自動調用自身的notifyAll方法喚醒A線程,從而達到同步的目的。

相關文章
相關標籤/搜索