Thread類中的join方法,用于等待某個執行緒執行結束,
簡單示例
以下簡單的代碼,會讓主執行緒等待子執行緒執行結束再執行,如果去掉t.join(),可能主執行緒就直接退出了,子執行緒都來不及執行,
package com.qcy.testJoin;
/**
* @author qcy
* @create 2020/09/10 17:17:03
*/
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t.start();
t.join();
}
}
join原始碼分析
t.join()原始碼如下:
public final void join() throws InterruptedException {
join(0);
}
接著是呼叫join的單引數多載方法,傳入等待時間0,表示一直等待下去
這一點也可以從多載方法的注釋中看到

單引數的多載方法如下:以主執行緒呼叫t.join()為例
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;
}
}
}
(1)由于這里出現了synchronized,因此主執行緒需要拿到子執行緒物件t的鎖,
(2)當millis為0的時候,回圈判斷isAlive(),即判斷執行緒是否存活,如果存活,呼叫子執行緒物件的wait方法,傳入0也是表示一直等待下去
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
*
* @return <code>true</code> if this thread is alive;
* <code>false</code> otherwise.
*/
public final native boolean isAlive();
(3)當主執行緒呼叫子執行緒物件的wait方法后,主執行緒釋放掉鎖,并進入等待狀態,
(4)當子執行緒運行結束,不再是存活狀態,那么主執行緒需要被喚醒,且需要再次獲取到鎖,才能繼續運行join剩余的方法,運行結束后,主執行緒從join方法中回傳,繼續運行main剩余的方法,
JVM底層代碼分析
問題來了,主執行緒什么時候被喚醒?喚醒代碼又是在哪里的呢?
這要看jvm的底層代碼,在thread.cpp代碼中,地址thread.cpp地址
在執行緒退出的代碼中,呼叫了ensure_join()方法
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
....
// Notify waiters on thread object. This has to be done after exit() is called
// on the thread (if the thread is the last thread in a daemon ThreadGroup the
// group should have the destroyed bit set before waiters are notified).
ensure_join(this);
....
// Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread
Threads::remove(this);
}
從ensure_join(this)上方的注釋可以了解到,該方法是喚醒在該執行緒物件上的等待者,繼續看他的原始碼
static void ensure_join(JavaThread* thread) {
// We do not need to grap the Threads_lock, since we are operating on ourself.
Handle threadObj(thread, thread->threadObj());
assert(threadObj.not_null(), "java thread object must exist");
ObjectLocker lock(threadObj, thread);
// Ignore pending exception (ThreadDeath), since we are exiting anyway
thread->clear_pending_exception();
// Thread is exiting. So set thread_status field in java.lang.Thread class to TERMINATED.
java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
// Clear the native thread instance - this makes isAlive return false and allows the join()
// to complete once we've done the notify_all below
java_lang_Thread::set_thread(threadObj(), NULL);
lock.notify_all(thread);
// Ignore pending exception (ThreadDeath), since we are exiting anyway
thread->clear_pending_exception();
}
java_lang_Thread::set_thread(threadObj(), NULL)陳述句,由上面的注釋,可以了解到該方法會清除本地執行緒實體,將會使得isAlive()回傳false,接著在呼叫完lock.notify_all(thread)陳述句后,即通知在此執行緒物件上的等待者,我們例子中的主執行緒在重新獲得CPU分配的時間片后,會直接從join方法中回傳,
其他方式
至此,我們了解到了join方法的原理,不過join我們很少用到,在主執行緒等待子執行緒執行結束再執行的場景下,有更好更優雅的方法,可以參考我的另外一篇博客面試官:如何讓主執行緒等待所有的子執行緒執行結束之后再執行?我懵了
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/33133.html
標籤:其他
