主线程调用子线程的 join() 方法可阻塞自身直至子线程结束;支持无限等待或超时等待,需在 start() 后调用,不可在子线程内自调用,多线程等待需依次 join,异常与中断需额外处理。

主线程调用子线程的 join() 方法,就能阻塞自己,直到该子线程执行结束。
join 的基本用法
join() 是 Thread 类的实例方法,调用后当前线程(比如主线程)会暂停执行,等待目标线程运行完成。它底层基于 wait() 实现,但无需手动同步,使用简单安全。
- 直接调用
thread.join():无限等待,直到子线程自然结束 - 调用
thread.join(timeout):最多等待指定毫秒数,超时后继续执行(即使子线程还没完) - 多个子线程需全部等待?依次对每个线程调用
join()即可
典型写法示例
启动多个子线程后,在主线程中挨个 join:
Thread t1 = new Thread(() -> { /* 耗时任务 */ });
Thread t2 = new Thread(() -> { /* 另一个任务 */ });
<p>t1.start();
t2.start();</p><p>// 主线程在此阻塞,等 t1 结束
t1.join();
// 再等 t2 结束
t2.join();</p><p>// 此处确保 t1 和 t2 都已执行完毕
System.out.println("所有子线程已完成");
注意 join 的调用时机和位置
join() 必须在子线程 start() 之后调用,否则无效(未启动的线程调用 join() 会立即返回);也不能在子线程内部对自己调用 join()(会导致死锁)。
立即学习“Java免费学习笔记(深入)”;
- 错误:在
start()前调用join()→ 不起作用 - 错误:在子线程 run 方法里写
this.join()→ 自己等自己,永远卡住 - 正确:主线程 start 后、业务逻辑收尾前调用
join()
替代方案与补充说明
如果子线程数量多或需更灵活控制,可考虑 CountDownLatch 或 CyclicBarrier;但简单场景下 join() 最轻量、最直观。
-
CountDownLatch更适合“等待 N 个任务全部完成”,尤其跨方法/跨类协调时 -
join()无法响应中断(除非用带超时版本并检查中断状态),而CountDownLatch.await()支持中断 - 若子线程抛出异常,
join()不会捕获,需在子线程内处理或通过其他方式传递异常信息


















