public final void join() throws InterruptedException
public final void join(long millis) throws InterruptedException
public final void join(long millis, int nanos) throws InterruptedException
語義:當前線程調用 targetThread.join() 後阻塞等待,直到 targetThread 終止(run 方法結束)或超時返回。
public class JoinDemo {
static class Worker extends Thread {
private final String name;
Worker(String name) { this.name = name; }
@Override public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(name + " - " + i);
try { Thread.sleep(200); } catch (InterruptedException ignored) {}
}
}
}
public static void main(String[] args) throws InterruptedException {
Worker a = new Worker("A");
Worker b = new Worker("B");
a.start();
a.join(); // 主線程阻塞,等 A 結束
b.start(); // A 結束後才啟動 B
b.join(); // 可選:等 B 結束再繼續主線程
System.out.println("主線程結束");
}
}
輸出:
A - 0
A - 1
A - 2
A - 3
A - 4
B - 0
B - 1
B - 2
B - 3
B - 4
主線程結束
// Thread.join()
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) throw new IllegalArgumentException("timeout < 0");
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(this) 鎖住 Thread 對象監視器。wait() 釋放鎖進入 WAITING 狀態。notifyAll() 喚醒所有在該 Thread 對象上 wait 的線程。join() 鎖的是 Thread 實例對象,業務代碼不要同步鎖定 Thread 對象,避免死鎖或干擾 join 喚醒。Thread task = new Thread(() -> {
try { Thread.sleep(5000); } catch (InterruptedException ignored) {}
});
task.start();
// 最多等 2 秒
task.join(2000);
if (task.isAlive()) {
System.out.println("任務超時,執行降級/補償邏輯");
// 可選:task.interrupt(); 嘗試中斷
} else {
System.out.println("任務正常完成");
}
| 誤區 | 正確理解 |
|---|---|
| join() 能強制終止目標線程 | 不能。join 只是等待;需配合 interrupt() + 目標線程響應中斷來實現取消。 |
| join() 返回代表線程「成功」結束 | 只代表線程「終止」(正常 return、拋未捕獲異常、被 kill 都算終止)。業務結果需通過共享變量/ Future / Callback 獲取。 |
| 在目標線程內部調用 this.join() | 死鎖!線程無法等待自己結束。JVM 檢測到會拋 IllegalThreadStateException(部分版本直接卡死)。 |
| 業務代碼 synchronized(threadInstance) | 極高風險:會阻塞 JVM 內部 notifyAll,導致 join 永不返回。請使用私有鎖對象。 |
| join(long) 精確到毫秒 | 受 OS 調度影響,精度通常 10-15ms(Windows)或 1ms(Linux)。不適合硬實時場景。 |
public class Aggregator {
public static void main(String[] args) throws InterruptedException {
List workers = new ArrayList<>();
Map results = new ConcurrentHashMap<>();
for (int i = 0; i < 3; i++) {
final int id = i;
Thread t = new Thread(() -> {
int sum = 0;
for (int j = 0; j < 1_000_000; j++) sum += j;
results.put("Worker-" + id, sum);
});
workers.add(t);
t.start();
}
// 等待所有完成
for (Thread t : workers) t.join();
System.out.println("全部完成:" + results);
}
}
現代替代方案:Java 8+ 推薦使用 CompletableFuture.allOf()、ExecutorService.invokeAll()、CountDownLatch,語義更清晰、異常傳播更完善、支持取消與組合。
join() 是線程間最簡單的「等待終止」協作原語。Thread 对象監視器 + wait/notifyAll。CompletableFuture / StructuredTaskScope (JDK 21+) 等高級並發 API。