CountDownLatch 不自动保证初始化完成前不执行任务,需手动将 await() 放在依赖初始化的代码前、countDown() 放在初始化结束后;主线程初始化完毕调用 countDown(),业务线程开头调用 await() 确保同步。

CountDownLatch 本身不“保证”任务初始化完成前不被执行,它只是提供一种同步机制,需要你主动设计执行逻辑来实现这个效果。关键在于把 await() 放在真正依赖初始化结果的代码之前,而把 countDown() 放在初始化完成的那一刻。
初始化线程里调用 countDown()
谁负责初始化,谁就在初始化逻辑结束后调用 countDown()。比如主线程做初始化:
- 创建 CountDownLatch(1)
- 启动子线程(或异步任务),同时主线程继续执行初始化工作
- 初始化完成后,主线程调用 latch.countDown()
业务逻辑线程里先 await() 再执行
任何需要等待初始化完成才能运行的代码,必须在开头调用 await()。例如:
- 新起一个线程处理业务,第一行就是
latch.await() - 如果是在回调、监听器或定时任务中执行,也要确保先等锁再干活
- 注意:await() 可能被中断,建议捕获 InterruptedException 并合理处理
避免常见误用
容易出问题的地方:
立即学习“Java免费学习笔记(深入)”;
- 忘记调用 countDown() → await() 永远阻塞
- 在初始化还没做完时就提前调用了 countDown() → 同步失效
- 多个线程都调用 await() 是安全的,但只有一个线程(或明确时机)调用 countDown() 才符合“初始化完成”语义
- 不要用 CountDownLatch 控制“多次初始化”,它是一次性的;重复使用应选 CyclicBarrier 或其他机制
简单示例结构
主线程初始化配置,Worker 线程必须等配置就绪才开始工作:
CountDownLatch latch = new CountDownLatch(1);
// 启动 Worker
new Thread(() -> {
try {
latch.await(); // 阻塞直到初始化完成
doWork(); // 正式执行
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// 主线程做初始化
loadConfig();
initDB();
latch.countDown(); // 通知所有 await 的线程可以继续


















