Thread.join() 是實現「線程順序執行」的關鍵方法:調用線程(通常是主線程)阻塞等待,直到目標線程運行結束。本文通過代碼示例演示 join() 行為,並補充線程優先級與 yield() 協作式調度知識。
class JoinTestDemo implements Runnable {
@Override
public void run() {
for (int x = 0; x <= 5; x++) {
try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(Thread.currentThread().getName() + "====" + x);
}
}
}
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
JoinTestDemo task = new JoinTestDemo();
Thread t1 = new Thread(task, "Thread-1");
Thread t2 = new Thread(task, "Thread-2");
t1.start();
t2.start();
// 主線程阻塞,等待 t1 完全結束
t1.join();
// t1 結束後,主線程繼續執行
for (int x = 0; x <= 5; x++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + "====" + x);
}
}
}

輸出順序:
Thread-1 和 Thread-2 交替輸出 0~5(併發運行)。Thread-1 運行結束(約 600ms)。t1.join() 返回,開始輸出 main====0~5。Thread-2 可能仍在運行,但主線程不再等待它(除非再調用 t2.join())。join():無限期等待。join(long millis):最多等待指定毫秒,超時返回(不拋異常,需自行檢查 isAlive())。join(long millis, int nanos):納秒級精度超時等待。join() 內部調用 wait(0) 循環,釋放鎖並進入 WAITING 狀態。目標線程終止時,JVM 自動調用 notifyAll() 喚醒等待線程。源碼片段:
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;
}
}
}
setPriority(int),範圍 1(MIN_PRIORITY)~10(MAX_PRIORITY),默認 5(NORM_PRIORITY)。僅是調度器參考提示,不保證執行順序。Thread.yield() 暫時放棄 CPU 時間片,讓同優先級線程有機會執行。屬協作式調度,不可靠,僅用於測試/調試。thread.join() 或使用 CountDownLatch/CompletableFuture.allOf() 更優雅。join(millis) 防止死等異常線程,超時後記錄日誌、發送告警、嘗試 interrupt()。join(),極易產生死鎖。