主线程等待子线程完成的本质是同步等待,推荐用countdownlatch(已知线程数)、executorservice.awaittermination(线程池任务完成)、completablefuture.allof(需返回值);不推荐thread.join()。

主线程等待所有子线程执行完成,本质是实现**同步等待**,而不是让主线程“轮询”或“sleep”。Java 中最常用、最推荐的方式是使用 CountDownLatch 或 CyclicBarrier,其次是 ExecutorService.awaitTermination() 配合 shutdown()。下面分场景说明:
用 CountDownLatch 控制主线程等待(推荐,简单明确)
适用于已知子线程数量的场景,比如启动 5 个任务,等全部结束再继续。
- 创建一个
CountDownLatch,计数值设为子线程总数(如 5) - 每个子线程执行完任务后调用
countDown() - 主线程调用
latch.await()—— 会阻塞直到计数归零
示例关键代码:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
CountDownLatch latch = new CountDownLatch(5);
ExecutorService pool = Executors.newFixedThreadPool(3);
for (int i = 0; i {
try {
// 执行子任务
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
latch.countDown(); // 必须放在 finally 中,确保执行
}
});
}
latch.await(); // 主线程在此等待所有子线程完成
System.out.println("所有子线程执行完毕");
pool.shutdown();
用 ExecutorService.awaitTermination() 等待线程池关闭
适用于使用线程池提交任务、且不关心具体线程数量,只关心“所有已提交任务是否完成”的场景。
- 调用
shutdown()表示不再接受新任务,但会继续执行已提交任务 - 再调用
awaitTermination(timeout, unit)等待指定时间,返回 true 表示已全部完成 - 建议配合超时和中断检查,避免无限等待
示例关键代码:
ExecutorService pool = Executors.newFixedThreadPool(3);
for (int i = 0; i {
try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
});
}
pool.shutdown(); // 发起关闭
if (!pool.awaitTermination(10, TimeUnit.SECONDS)) {
pool.shutdownNow(); // 超时则尝试强制终止
}
System.out.println("线程池已关闭,所有任务完成");
用 CompletableFuture.allOf()(适合有返回值的任务)
如果子任务需要返回结果,且希望主线程等全部完成后再统一处理结果,CompletableFuture 是更现代、函数式的选择。
- 每个任务包装成
CompletableFuture<t></t> - 用
CompletableFuture.allOf(futures...)组合所有 future - 调用
join()阻塞等待全部完成(不抛受检异常) - 再通过
future.get()获取各结果
示例关键代码:
List<completablefuture>> futures = new ArrayList();
for (int i = 0; i {
try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
return "result-" + i;
}));
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
// 收集结果
List<string> results = futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
System.out.println(results);
</string></completablefuture>
不推荐的做法:Thread.join()(仅限手动 new Thread)
如果没用线程池,而是直接 new Thread(runnable).start(),可用 join(),但需注意:
- 必须保存每个
Thread引用,逐一调用join() - 无法与线程池共用(
ExecutorService提交的是Runnable,不暴露底层Thread) - 缺乏超时控制,容易卡死;也不支持批量等待
因此,除非极简场景,否则不建议在生产中使用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










