多執行緒之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