目录
一、CyclicBarrier简介
CyclicBarrier 是 Java 并发包中的一个同步工具类,位于 java.util.concurrent 包中。允许一组线程相互等待,直到所有线程都到达某个公共的屏障点(barrier)。一旦所有线程都到达屏障, CyclicBarrier 会释放所有等待的线程,使它们继续执行。
CyclicBarrier 主要用于协调多个线程的执行。它的构造函数需要一个整数参数,表示参与屏障的线程数量。主要方法包括:
await():使当前线程等待,直到所有参与线程都调用了此方法。
getNumberWaiting():返回当前在等待屏障的线程数量。
getParties():返回屏障的总参与线程数量。
reset():重置屏障,使其可以被重新使用。
二、CyclicBarrier原理
CyclicBarrier 的原理是通过维护一个计数器来跟踪有多少线程已经到达屏障。当一个线程调用 await() 方法时,它会被阻塞,直到所有参与的线程都调用了 await() 。一旦所有线程都到达屏障,计数器会被重置,所有等待的线程会被释放,继续执行。
CyclicBarrier 是可重用的,即在所有线程到达屏障后,可以再次使用该屏障。
三、CyclicBarrier使用场景
1. 分阶段的并行任务
在某些情况下,多个线程需要在完成某个阶段的任务后再一起执行下一阶段的任务。
2. 并行计算
在大规模并行计算中,可以使用 CyclicBarrier 来协调多个线程的执行,例如在每个计算阶段结束时同步结果。
四、与 CountDownLatch 的区别
CountDownLatch也是等待一组线程执行完毕,两者的区别如下:
可重用性: CyclicBarrier 是可重用的,所有线程到达屏障后可以再次使用。而 CountDownLatch 一旦计数器减为零,就不能再重置。
使用场景: CountDownLatch 更适合用于等待多个线程完成某项任务,而 CyclicBarrier 更适合用于多个线程之间的相互等待和同步。
计数机制: CountDownLatch 使用的是减法计数,而 CyclicBarrier 使用的是到达计数,所有线程到达后才释放。
五、CyclicBarrier用法
下面使用 CyclicBarrier 实现如何在多个线程之间协调执行:
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
private static final int THREAD_COUNT = 3;
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT, () -> {
// 所有线程到达屏障后执行的操作
System.out.println("所有线程已到达屏障,继续执行下一阶段。");
});
// 创建并启动多个线程
for (int i = 0; i < THREAD_COUNT; i++) {
final int threadIndex = i;
new Thread(() -> {
try {
System.out.println("线程 " + threadIndex + " 正在工作...");
Thread.sleep((long) (Math.random() * 1000)); // 模拟工作
System.out.println("线程 " + threadIndex + " 到达屏障。");
barrier.await(); // 等待其他线程到达屏障
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
结果如下:
如上,首先初始化 CyclicBarrier ,并指定参与的线程数量( THREAD_COUNT )以及所有线程到达屏障后执行的操作(Runnable), 在循环中创建多个线程,每个线程模拟一个任务的执行,每个线程在完成工作后调用 barrier.await() ,等待其他线程到达屏障,所有线程都到达屏障后,指定的操作会被执行,随后所有线程继续执行,与 CountDownLatch 相比, CyclicBarrier 更适合用于分阶段的任务执行和多线程之间的同步。