Java中的CyclicBarrier是java.util.concurrent包下提供的同步辅助类,它的作用是让一组线程互相等待,直到所有线程都到达某个公共屏障点之后,才会继续执行后续的逻辑。和CountDownLatch不同,CyclicBarrier是可以重复使用的,所以也被称为循环栅栏。

CyclicBarrier的核心构造方法
CyclicBarrier主要有两个常用的构造方法,开发者可以根据需求选择使用:
- CyclicBarrier(int parties):创建一个循环栅栏,参数parties表示需要等待的线程数量,当到达的线程数量达到这个值的时候,所有等待的线程就会被唤醒继续执行。
- CyclicBarrier(int parties, Runnable barrierAction):在上面的构造方法基础上,增加一个屏障动作,当所有线程都到达屏障点之后,会先执行这个barrierAction的逻辑,再唤醒所有等待的线程。
CyclicBarrier的常用API
除了构造方法之外,CyclicBarrier还有几个常用的方法:
- await():线程调用这个方法之后会进入等待状态,直到所有线程都调用了await方法。
- await(long timeout, TimeUnit unit):带超时的等待方法,如果超过指定的时间还没有所有线程到达,就会抛出TimeoutException。
- getParties():获取需要等待的线程总数。
- getNumberWaiting():获取当前已经到达屏障点的线程数量。
- reset():重置循环栅栏,会让所有正在等待的线程抛出BrokenBarrierException。
CyclicBarrier基础使用示例
下面通过一个简单的示例演示CyclicBarrier的基本使用,我们创建3个线程,每个线程执行完自己的任务之后调用await方法等待,直到3个线程都到达之后,再一起执行后续逻辑。
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
public static void main(String[] args) {
// 创建循环栅栏,需要等待3个线程,所有线程到达后先打印"所有线程已到达屏障点"
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程已到达屏障点,准备继续执行");
});
// 创建3个线程
for (int i = 0; i < 3; i++) {
int threadId = i;
new Thread(() -> {
try {
System.out.println("线程" + threadId + "开始执行任务");
// 模拟线程执行任务的耗时
Thread.sleep((threadId + 1) * 1000);
System.out.println("线程" + threadId + "任务执行完成,到达屏障点等待");
// 调用await方法等待其他线程
cyclicBarrier.await();
System.out.println("线程" + threadId + "继续执行后续逻辑");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
运行上面的代码,输出结果如下,可以看到三个线程各自执行完任务之后都会等待,直到三个都到达之后才一起执行后续逻辑:
线程0开始执行任务 线程1开始执行任务 线程2开始执行任务 线程0任务执行完成,到达屏障点等待 线程1任务执行完成,到达屏障点等待 线程2任务执行完成,到达屏障点等待 所有线程已到达屏障点,准备继续执行 线程2继续执行后续逻辑 线程0继续执行后续逻辑 线程1继续执行后续逻辑
CyclicBarrier的循环使用特性
CyclicBarrier之所以被称为循环栅栏,是因为它在使用完一次之后可以自动重置,不需要手动重新创建就可以再次使用。下面的示例演示它的循环特性,我们让一组线程重复两次到达屏障点:
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierReuseDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> {
System.out.println("本轮所有线程已到达屏障点,开始下一轮");
});
for (int i = 0; i < 2; i++) {
int round = i;
new Thread(() -> {
try {
for (int j = 0; j < 2; j++) {
System.out.println("线程" + round + "开始第" + j + "轮任务");
Thread.sleep(1000);
System.out.println("线程" + round + "第" + j + "轮任务完成,到达屏障点");
cyclicBarrier.await();
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
运行之后可以看到,两次循环中所有线程都会先互相等待,到达屏障点之后再继续执行下一轮,不需要重新创建CyclicBarrier实例。
CyclicBarrier的典型应用场景
1. 分治任务处理
当把一个大任务拆分成多个子任务分给不同线程处理的时候,需要等到所有子任务都处理完成之后,再汇总结果做后续处理,这种场景就非常适合使用CyclicBarrier。比如我们需要计算一个大数组中所有元素的和,可以把数组拆分成几个部分,每个线程计算一部分的和,所有线程计算完成之后,再汇总各个部分的结果得到最终的和。
import java.util.concurrent.CyclicBarrier;
public class SumCalculateDemo {
private static final int PART_COUNT = 4;
private static int[] result = new int[PART_COUNT];
public static void main(String[] args) {
int[] data = new int[100];
// 初始化数组,赋值1到100
for (int i = 0; i < 100; i++) {
data[i] = i + 1;
}
CyclicBarrier cyclicBarrier = new CyclicBarrier(PART_COUNT, () -> {
// 所有子任务计算完成,汇总结果
int total = 0;
for (int num : result) {
total += num;
}
System.out.println("数组所有元素的总和为:" + total);
});
// 拆分任务,每个线程计算一部分
int partSize = data.length / PART_COUNT;
for (int i = 0; i < PART_COUNT; i++) {
int start = i * partSize;
int end = (i == PART_COUNT - 1) ? data.length : start + partSize;
int partIndex = i;
new Thread(() -> {
try {
int sum = 0;
for (int j = start; j < end; j++) {
sum += data[j];
}
result[partIndex] = sum;
System.out.println("子任务" + partIndex + "计算完成,部分和为:" + sum);
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
2. 多阶段计算任务
有些计算任务需要分多个阶段执行,每个阶段都需要所有线程都完成当前阶段的任务,才能进入下一个阶段,这种场景也可以使用CyclicBarrier。比如一个数据处理任务,第一阶段是数据清洗,第二阶段是数据转换,第三阶段是数据入库,每个阶段都需要所有线程完成当前阶段的工作再统一进入下一阶段。
3. 模拟并发测试
在做接口并发测试的时候,需要让多个线程在同一时刻同时发起请求,就可以使用CyclicBarrier。让所有线程准备好之后都调用await方法等待,直到所有线程都准备好,再同时释放,这样就可以模拟出同一时刻的并发请求。
使用CyclicBarrier的注意事项
- 如果参与等待的线程数量少于构造方法里设置的parties值,那么所有调用await的线程都会一直等待,除非调用了reset方法或者有线程被中断。
- 如果等待过程中有线程被中断、超时或者调用了reset方法,其他正在等待的线程会抛出BrokenBarrierException,此时CyclicBarrier会被损坏,需要重置之后才能继续使用。
- 如果构造方法里设置了barrierAction,那么这个动作是由最后一个到达屏障点的线程执行的,要注意这个动作里不要有耗时的操作,否则会影响所有线程的唤醒时间。
CyclicBarrier和CountDownLatch的区别:CountDownLatch是倒计时器,一个线程等待多个线程完成之后再执行,或者多个线程等待一个线程的信号,不能重复使用;而CyclicBarrier是一组线程互相等待,所有线程到达之后一起执行,并且可以循环重复使用。
CyclicBarrier多线程同步循环栅栏线程屏障修改时间:2026-06-14 06:00:46