









CountDownLatch 和 CyclicBarrier 这两个 Java 并发工具类的核心区别,我会从定义、使用场景、核心特性等方面帮你清晰梳理。
先通过简单的比喻理解两者:
| 特性 | CountDownLatch | CyclicBarrier |
|---|---|---|
| 核心作用 | 一个 / 多个线程等待其他线程完成操作 | 多个线程互相等待,直到所有线程都到达屏障点 |
| 可复用性 | 计数器归 0 后无法重置,只能用一次 | 屏障触发后可自动重置,能重复使用 |
| 触发条件 | 计数器 countDown() 到 0 触发 |
指定数量的线程调用 await() 到达屏障触发 |
| 等待方 | 可以是一个或多个线程等待 | 参与的线程互相等待(都是等待方) |
| 额外功能 | 无回调函数 | 支持屏障触发时执行指定的回调任务 |
| 底层实现 | 基于 AQS 的共享模式 | 基于 ReentrantLock + Condition |
场景:主线程等待 3 个工作线程全部完成任务后,再执行汇总操作。
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
// 初始化计数器为 3(对应 3 个工作线程)
CountDownLatch latch = new CountDownLatch(3);
// 启动 3 个工作线程
for (int i = 1; i <= 3; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 执行任务中...");
Thread.sleep(1000); // 模拟任务耗时
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown(); // 任务完成,计数器减 1
System.out.println(Thread.currentThread().getName() + " 任务完成,计数器剩余: " + latch.getCount());
}
}, "线程" + i).start();
}
// 主线程等待计数器归 0
latch.await();
System.out.println("所有工作线程任务完成,主线程执行汇总操作");
}
}
输出(顺序可能略有不同):
线程1 执行任务中...
线程2 执行任务中...
线程3 执行任务中...
线程1 任务完成,计数器剩余: 2
线程2 任务完成,计数器剩余: 1
线程3 任务完成,计数器剩余: 0
所有工作线程任务完成,主线程执行汇总操作
场景:3 个运动员线程,每次都要等所有人到起跑线(屏障点)才能一起起跑,且支持重复比赛(屏障重置)。
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static void main(String[] args) {
// 初始化屏障:3 个线程到达后触发,且触发时执行回调任务(打印起跑提示)
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("===== 所有运动员已就位,开始起跑!=====\n");
});
// 定义运动员任务
Runnable runner = () -> {
try {
for (int i = 1; i <= 2; i++) { // 模拟 2 轮比赛
System.out.println(Thread.currentThread().getName() + " 到达起跑线,等待其他运动员(第" + i + "轮)");
barrier.await(); // 到达屏障,等待其他线程
System.out.println(Thread.currentThread().getName() + " 开始跑步(第" + i + "轮)");
Thread.sleep(500); // 模拟跑步耗时
}
} catch (Exception e) {
e.printStackTrace();
}
};
// 启动 3 个运动员线程
new Thread(runner, "运动员A").start();
new Thread(runner, "运动员B").start();
new Thread(runner, "运动员C").start();
}
}
输出:
运动员A 到达起跑线,等待其他运动员(第1轮)
运动员B 到达起跑线,等待其他运动员(第1轮)
运动员C 到达起跑线,等待其他运动员(第1轮)
===== 所有运动员已就位,开始起跑!=====
运动员C 开始跑步(第1轮)
运动员A 开始跑步(第1轮)
运动员B 开始跑步(第1轮)
运动员A 到达起跑线,等待其他运动员(第2轮)
运动员B 到达起跑线,等待其他运动员(第2轮)
运动员C 到达起跑线,等待其他运动员(第2轮)
===== 所有运动员已就位,开始起跑!=====
运动员C 开始跑步(第2轮)
运动员B 开始跑步(第2轮)
运动员A 开始跑步(第2轮)
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。