countdownlatch适用于只等待任务完成而不获取结果的场景,future.get()适用于需获取并校验每个任务结果的场景;两者可组合使用,但future语义更完整,推荐优先使用。

异步任务执行后需要等待所有结果再统一处理,本质是“等齐”多个并发流。CountDownLatch 和 Future.get 都能实现同步等待,但适用场景和控制粒度不同:前者适合纯等待、不关心返回值;后者适合需获取计算结果的场景。
CountDownLatch:适用于“只等完成、不取结果”的汇聚
当你启动一批异步任务(比如发多条日志、触发多个通知),仅需确保它们全部执行完毕再继续后续流程,而无需每个任务的返回值时,CountDownLatch 最简洁。
- 初始化时传入任务总数(如
new CountDownLatch(3)) - 每个异步任务结尾调用
countDown() - 主线程调用
latch.await()阻塞直到计数归零 - 注意:若某任务异常未执行
countDown(),主线程会永久阻塞——建议配合超时(await(10, TimeUnit.SECONDS))和异常兜底
Future.get():适用于“要结果、且需逐个校验”的汇聚
当你使用 ExecutorService.submit() 提交 Callable 任务,返回一组 Future<t></t>,就需要通过 get() 拿结果并聚合。它天然支持异常传播和超时控制。
- 提交任务后保存所有 Future 到列表中
- 遍历调用
future.get(timeout, unit),可统一设超时避免某个任务拖慢整体 - 捕获
ExecutionException(包装业务异常)、TimeoutException、CancellationException分类处理 - 若允许部分失败,可用
isDone()或isCancelled()辅助判断状态再决定是否跳过
组合使用:兼顾等待 + 结果 + 容错
实际中常混合使用:用 CountDownLatch 快速感知“全部结束”,再用 Future.get() 按需提取结果。更推荐直接依赖 Future.get(),因为它的语义更完整——既是同步点,也是结果入口。
- 避免为省一行代码而用 CountDownLatch 替代 Future,丢失结果和异常信息
- 若任务本身无返回值(Runnable),又确实需要结果上下文,可封装成返回空对象或状态码的 Callable
- 对高吞吐场景,考虑用
CompletableFuture.allOf()替代手动管理 Future 列表,写法更函数式且支持链式回调
不复杂但容易忽略:超时设置和异常分类处理,才是让“异步转同步”真正可靠的关键。










