Thread.join()用于让当前线程等待指定线程执行完毕后再继续执行;需保存子线程引用并遍历调用join(),配合线程安全容器或原子类汇总结果,同时妥善处理InterruptedException和子线程异常。

在 Java 中,Thread.join() 是让当前线程(比如主线程)**等待指定线程执行完毕后再继续执行**的最直接方式。要确保主线程在所有子计算线程完成后再汇总结果,关键在于:启动所有子线程后,对每个子线程调用 join(),且必须在汇总逻辑之前完成所有 join() 调用。
正确启动并收集子线程引用
不能只靠 new Thread(...).start() 就完事——那样会丢失线程引用,无法后续调用 join()。必须把每个 Thread 实例保存下来(例如放进 List)。
示例:
List<thread> workers = new ArrayList();
for (int i = 0; i {
// 模拟子任务:计算、IO 或其他耗时操作
int result = computeSomething();
// 注意:需安全共享结果(见下一点)
sharedResults.add(result);
});
workers.add(t);
t.start();
}
</thread>
在主线程中顺序或并发调用 join()
遍历保存的线程列表,对每个线程调用 join()。这会阻塞主线程,直到该子线程结束。多个 join() 可以按任意顺序调用,不影响最终等待效果。
常见写法:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
-
简单顺序等待:逐个调用
t.join(),代码清晰,适用于线程数不多的场景 -
带超时的等待:用
t.join(5000)防止某个子线程卡死导致主线程无限挂起 - 不推荐“边 start 边 join”:那会变成串行执行,失去多线程意义
安全地汇总子线程结果
子线程之间不能直接修改同一个变量(如普通 int sum),否则有竞态风险。推荐以下几种方式:
-
使用线程安全容器:如
CopyOnWriteArrayList、ConcurrentLinkedQueue,或加锁的ArrayList -
每个子线程返回独立结果,主线程最后合并:配合
Callable+Future(更推荐,但不属于join()原生方案) -
用原子类:如
AtomicInteger累加标量结果
例如:
List<integer> sharedResults = Collections.synchronizedList(new ArrayList());
// … 启动线程(如上)…
for (Thread t : workers) {
try {
t.join(); // 等待每个子线程结束
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
int total = sharedResults.stream().mapToInt(Integer::intValue).sum(); // 汇总
</integer>
注意异常与中断处理
join() 可能抛出 InterruptedException,说明当前线程被其他线程中断。应合理响应:通常恢复中断状态(Thread.currentThread().interrupt()),并考虑是否提前退出等待流程。
另外,若子线程本身抛出未捕获异常,它只会打印堆栈,并不会传播给主线程——所以务必在子线程内做好异常日志或错误标记,避免“看似完成实则失败”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










