join()阻塞调用它的线程,如主线程调用t1.join()则主线程暂停等待t1结束;错误地调用thread.currentthread().join()会导致当前线程自等待而永久阻塞。

Java 中 join() 方法会让调用它的线程(比如主线程)暂停执行,直到目标线程运行结束。它本身不是“阻塞主线程”的问题,而是设计上就用来实现等待——关键在于你是否需要这种等待,以及是否误用了它。
join() 阻塞的是谁?
只阻塞调用 join() 的那个线程,和其他线程无关。例如:
-
t1.join()在主线程中执行 → 主线程停住,等t1结束;t2仍可正常运行。 -
t1.join()在t2的run()方法里执行 → 是t2被挂起,不是主线程。 - 错误写法:
Thread.currentThread().join()→ 当前线程等自己,永远卡住,形成自死锁。
主线程被意外阻塞的常见原因
不是 join() 本身有问题,而是用法偏离预期:
- 在启动子线程后立刻调用
join(),且没做任何异步处理,导致主线程全程空等。 - 多个
join()串行调用(如t1.join(); t2.join();),主线程要等完一个再等下一个,总耗时是累加的。 - 未捕获
InterruptedException,或忽略中断状态,使线程无法响应外部停止信号。
规避主线程长时间阻塞的实用技巧
不一定要放弃 join(),关键是让它更可控:
- 用带超时的
join(long millis),比如t1.join(3000),最多等 3 秒,超时后继续执行,避免无限等待。 - 把多个子线程的
join()放在循环里,但注意:它们是顺序等待的;若想并行等待全部完成,可先start()全部,再统一join()(即先启再等)。 - 对结果有依赖但又不想卡主线程?改用
CompletableFuture或CountDownLatch,让主线程做其他事,等通知再取结果。 - 如果只是为读取子线程计算的变量(如
r = 10),确保该变量是volatile或用同步机制保护,避免因指令重排序或缓存导致读到旧值。
什么时候其实不该用 join()
当业务逻辑不要求“严格顺序等待”时,硬加 join() 反而降低并发效率:
- 日志上报、埋点采集等非关键路径任务,启动后无需等待,直接返回即可。
- UI 线程中调用
join()会导致界面冻结,应改用回调、Handler、LiveData 或协程等异步通信方式。 - 后台服务中需同时处理多个 I/O 操作,更适合用线程池 +
Future批量提交与收集结果。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











