1. 程式人生 > >多執行緒之join方法

多執行緒之join方法

一.前言:

       在很多情況下,我們都是通過主執行緒建立並啟動子執行緒的,如果子執行緒中需要耗費大量的時間計算的話,主執行緒往往會比子執行緒先結束,這個時候就會導致有時候主執行緒想獲取子執行緒計算之後的結果,但是卻獲取不到。這個時候,我們就可以通過join方法來解決這個問題。

二.join方法的作用:

join方法的作用是使所屬的執行緒物件x正常執行run()方法中的任務,而使當前執行緒z進行無限期的阻塞,等待執行緒x銷燬後再繼續執行執行緒z後面的程式碼。方法join具有使執行緒排隊執行的作用,有些類似同步的執行效果。

下面看一個例子:

public class MyThread extends Thread{
    @Override
    public void run() {
        int sencondValue = (int)(Math.random()*1000);
        System.out.println(sencondValue);
        try {
            Thread.sleep(sencondValue);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        myThread.join();
        System.out.println("當物件myThread執行完畢後再執行");
    }
}

執行結果:

join的意思是使得放棄當前執行緒的執行,並返回對應的執行緒,例如上面程式碼的意思就是:程式在main執行緒中呼叫myThread執行緒的join方法,則main執行緒放棄cpu控制權,並返回t1執行緒繼續執行直到執行緒t1執行完畢。所以結果是t1執行緒執行完後,才到主執行緒執行,相當於在main執行緒中同步t1執行緒,t1執行完了,main執行緒才有執行的機會 此外,join方法和interrupt方法相遇的時候會丟擲異常。

此外,還有join(long millis)方法,指定要等待多長時間。

三.join的實現原理:

檢視join方法原始碼:

/**
     * Waits for this thread to die.
     *
     * <p> An invocation of this method behaves in exactly the same
     * way as the invocation
     *
     * <blockquote>
     * {@linkplain #join(long) join}{@code (0)}
     * </blockquote>
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    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方法實際上是通過呼叫wait方法, 來實現同步的效果的。例如,A執行緒中呼叫了B執行緒的join方法,則相當於A執行緒呼叫了B執行緒的wait方法,在呼叫了B執行緒的wait方法後,A執行緒就會進入阻塞狀態,因為它相當於放棄了CPU的使用權。需要注意的是,jdk規定,join(0)的意思不是A執行緒等待B執行緒0秒,而是A執行緒等待B執行緒無限時間,直到B執行緒執行完畢,即join(0)等價於join()。

四.join方法和synchronized、sleep方法的區別:

1.從上面的原始碼我們可以看出,join(long millis)是通過在內部使用wait(long millis)方法來實現的,所有它其實是具有釋放鎖的特點的,在執行完;而sleep(long millis)是不釋放鎖的,也就是如果有Synchronized同步塊,其他執行緒仍然不能訪問共享資料。注意該方法要捕獲異常。

2.join在內部使用wait()方法進行等待,而synchronized關鍵字使用的是“物件監控器”原理做同步,具體可以看這個synchronized原理

 

參考:https://www.2cto.com/kf/201608/543154.html

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