countdownlatch是java中用于等待多个事件完成的倒计时同步工具,构造时指定计数,countdown()原子减1,await()阻塞至归零且不可重置。

CountDownLatch 是 Java 并发编程中最常用、最直观的同步工具之一,核心价值在于“等待多个事件完成”。它不负责任务调度或资源共享,而是专注解决“主线程等子线程干完再继续”这类协调问题。用对了,代码清晰;用错了,容易卡死或逻辑错乱。
CountDownLatch 的关键行为必须清楚
它不是锁,也不是信号量,而是一个倒计时门闩:
- 构造时指定一个正整数(如
new CountDownLatch(5)),代表要等待的事件总数; - 每个完成事件的线程调用
countDown(),计数器原子性减 1; - 调用
await()的线程会阻塞,直到计数器变为 0,之后所有等待线程被唤醒并继续执行; - 计数器归零后不可重置——这是它和
CyclicBarrier的本质区别,用完即弃。
典型使用场景与写法要点
常见于“分任务→并行执行→汇总结果”流程,比如批量查询、初始化检查、压力测试准备等:
- 主线程创建
CountDownLatch,传入子任务数量; - 每个子线程执行完自己那部分逻辑后,务必调用
countDown()(建议放在finally块中,避免异常跳过); - 主线程在合适位置调用
await(),等待全部完成; - 若业务不能无限等待,优先用带超时的
await(long, TimeUnit),返回false表示超时,可做降级或告警处理。
避免踩坑的实操细节
看似简单,但几个细节决定是否稳定可用:
-
不要漏调 countDown:某个子线程没执行到
countDown()(比如抛异常未捕获),主线程就会永久阻塞; -
不要多调 countDown:虽然多减不影响功能(计数器可为负),但会掩盖逻辑错误,且
getCount()返回负值不利于监控排查; -
await() 可被中断:调用方需正确处理
InterruptedException,通常恢复中断状态(Thread.currentThread().interrupt()); -
别和 join 混用:
Thread.join()是线程级等待,CountDownLatch是事件级等待,后者更灵活(不限于线程生命周期,可跨线程池、异步回调等场景)。
一个简洁可靠的模板写法
适用于大多数服务端并发汇总场景:
CountDownLatch latch = new CountDownLatch(taskList.size());
for (Task task : taskList) {
executor.submit(() -> {
try {
task.execute();
} finally {
latch.countDown(); // 确保执行
}
});
}
try {
if (!latch.await(10, TimeUnit.SECONDS)) {
log.warn("等待子任务超时,已触发降级");
// 执行超时策略,如返回缓存结果或空数据
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("主线程被中断", e);
}Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











