當前線程調用目標線程的 join(),將阻塞當前線程,直到目標線程運行結束 (正常結束或拋出異常終止)。
本質:this.wait(0) 循環等待 this.isAlive() == false,目標線程結束時 JVM 自動調用 this.notifyAll() 喚醒等待者。
public final void join() throws InterruptedException // 無限等待 public final synchronized void join(long millis) throws InterruptedException // 毫秒級超時 public final synchronized void join(long millis, int nanos) throws InterruptedException // 納秒級補充
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Worker: " + i);
try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
System.out.println("Worker finished");
}, "Worker-Thread");
worker.start();
System.out.println("Main: wait for worker...");
worker.join(); // 主線程阻塞在此,直到 worker 結束
System.out.println("Main: worker joined, continue...");
}
}
Main: wait for worker... Worker: 0 Worker: 1 Worker: 2 Worker: 3 Worker: 4 Worker finished Main: worker joined, continue...
worker.start();
boolean finished = worker.join(2000); // 最多等待 2 秒
if (finished) {
System.out.println("Worker completed in time");
} else {
System.out.println("Worker still running, main continue..."); // 主線程繼續,worker 後台繼續跑
}
| 誤區 | 正確理解 |
|---|---|
| join() 能中斷目標線程 | 不能。只能等待。需目標線程配合 interrupt() 並在代碼中檢查 Thread.interrupted()。 |
| join() 釋放鎖 | join() 內部用 wait(),會釋放當前對象鎖 (即 Thread 實例鎖),但不釋放其他 synchronized 鎖。 |
| 調用 join() 的線程持有目標線程鎖 | 無關。join() 鎖的是 Thread 實例 (this),業務鎖另算。 |
| 主線程 join 子線程後,子線程異常會傳播 | 不會。子線程異常需通過 Thread.UncaughtExceptionHandler 或 Future.get() 捕獲。 |
join() 逐個等待收集結果,再進行彙總計算。serviceAThread.join() 再啟動核心邏輯。workerThread.join(timeout) 等待工作線程處理完隊列任務再退出。join() 等待斷言條件滿足。| 工具 | 適用場景 | 優勢 |
|---|---|---|
| Thread.join() | 單一線程等待另一線程結束 | API 簡單、無額外依賴、JDK 1.0 即有 |
| CountDownLatch | 一個/多個線程等待 N 個任務完成 | 計數器語義、可等待多線程、可中斷等待 |
| CompletableFuture | 異步編排、組合、異常處理、回調 | 函數式風格、支持 thenApply/thenCompose/allOf/anyOf |
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;
}
}
}
關鍵點:synchronized 保證 isAlive() 與 wait() 原子性;notifyAll() 在線程終止時由 JVM 自動調用 (Thread.exit() 內部)。