java中runnable配合countdownlatch可实现线程“齐步走”,即全部就绪后统一启动或全部完成后统一汇总;需用startlatch控制并发起点,endlatch等待全部结束,并在finally中调用countdown()确保计数准确。

Java中用Runnable配合CountDownLatch,可以让多个线程在某个关键点“齐步走”——即全部准备就绪后才一起开始执行,或全部完成后再统一继续后续操作。核心思路是:用CountDownLatch做同步栅栏,Runnable封装线程任务,两者结合控制并发节奏。
用CountDownLatch实现“全部就绪后才启动”
适用于需要所有线程初始化完毕、加载好资源,再集体开始处理的场景(比如模拟并发压测、分布式节点协同启动)。
- 主线程创建CountDownLatch,计数器设为线程总数(如5个线程就设为5)
- 每个Runnable任务开头调用latch.await()——线程会在此阻塞,等待计数归零
- 主线程在启动所有线程后,调用latch.countDown()一次(或用latch = new CountDownLatch(0)直接放行)
- 更常用的是:主线程先启动线程,等所有线程进入await状态后,再调用countDown()触发集体执行
用CountDownLatch实现“全部完成后再汇总”
这是更典型的用法:主线程等待所有子线程跑完,再做结果合并、统计或关闭资源。
- 创建CountDownLatch,计数器等于线程数(如new CountDownLatch(3))
- 每个Runnable任务结尾调用latch.countDown()(确保finally块中执行,防异常跳过)
- 主线程调用latch.await(),阻塞直到计数归零,之后安全执行后续逻辑
- 可加超时控制:latch.await(10, TimeUnit.SECONDS),避免无限等待
Runnable + CountDownLatch 的典型组合写法
避免匿名内部类导致的变量捕获问题,推荐用局部变量+final语义或Lambda表达式:
CountDownLatch startLatch = new CountDownLatch(1); // 控制同时启动
CountDownLatch endLatch = new CountDownLatch(threadCount);
for (int i = 0; i {
try {
startLatch.await(); // 等待统一发令
// 执行业务逻辑……
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
endLatch.countDown(); // 保证计数一定减少
}
});
t.start();
}
// 所有线程已启动,现在发令
startLatch.countDown();
// 主线程等待全部结束
endLatch.await();
System.out.println("所有线程执行完毕");
注意事项与避坑点
- CountDownLatch不可重用:一旦计数归零,再次await()会立即返回;需重新new实例
- 务必在Runnable的finally中调用countDown(),否则某线程异常退出会导致主线程永久阻塞
- 不要在多个线程里重复调用同一个latch的countDown()多次(除非设计如此),容易误减导致提前释放
- 若需反复同步(如多轮批量处理),考虑用CyclicBarrier替代
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











