countDownLatch初了解
·
CountDownLatch使用场景和原理
说明:CountDownLatch 是 JUC(java.util.concurrent)包里 “一次性门闩” 同步器,一个/多个线程 在门闩上 await() 等待;另一个/另一些线程 执行完业务后 countDown() 把计数减到 0,门闩瞬间打开,所有等待线程同时通过,且 不能重复使用
。
使用场景:等所有人干完活再一起继续”
-
主线程等待所有子任务完成
-批量导入、并行计算、多线程文件解析。 -
多线程压测/预热
-让数千线程 同时 开始发请求(先 await,再一起 countDown)。 -
服务启动依赖
-微服务启动前必须 等待 DB、Redis、MQ 健康检查 全部 OK。
原理:底层 AQS 共享模式:(此处还有待理解)
await() → 如果 state > 0 则排队并 park;
countDown() → CAS 把 state–;当 state == 0 时 unpark 所有等待线程;
状态归零后 不再接受任何 countDown,门闩永远打开 → 一次性。
API说明:
| 方法 | 说明 |
|---|---|
| new CountDownLatch(int count) | 构造时指定“倒计数”初始值 |
| void await() / await(long timeout, TimeUnit unit) | 等待计数变 0/等待timeout时间 |
| void countDown() | 业务线程执行完调用,计数减 1 |
永久阻塞的几种方式:
- new CountDownLatch(1).await(); //计数器的值是1,没有调用countDown方法, 1 永远减不到 0 ,实现永久阻塞;
new CountDownLatch(0).await();// 实现原理同上- new CountDownLatch(1).await(10, TimeUnit.MINUTES); // 10 分钟后自动放行,时间可自定义
与 CyclicBarrier 区别
| 维度 | CountDownLatch | CyclicBarrier |
|---|---|---|
| 方向 | 倒计时到 0 | 计数加到指定值 |
| 重用性 | 一次性 | 可循环使用 |
| 等待角色 | 一个/多个线程 等别人 | 所有线程 互相等 |
| 典型场景 | 主线程等子任务 | 多线程 同时 开始/分段计算 |
示例:
public class Demo {
public static void main(String[] args) throws InterruptedException {
final int N = 5;
CountDownLatch latch = new CountDownLatch(N);
ExecutorService pool = Executors.newFixedThreadPool(N);
for (int i = 0; i < N; i++) { // 循环N次,每次在线程池中提交一个任务
final int idx = i;
pool.submit(() -> {
try {
// 模拟业务
System.out.println("task-" + idx + " 开始");
Thread.sleep(1000);
System.out.println("task-" + idx + " 结束");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
latch.countDown(); // 必须放在 finally;每个线程执行完一次,计数器就减1
}
});
}
latch.await(); // 主线程等待,等到计数器的值=0后,打印下面的日志
System.out.println("countDownLatch=0,所有线程均已完成,主线程池继续跑");
pool.shutdown();
}
}
执行结果:
更多推荐
所有评论(0)