Java中的CyclicBarrier概述
CyclicBarrier
是 Java 并发包 java.util.concurrent
里的同步工具类。它允许一组线程在到达某个公共屏障点(common barrier point)时相互等待,直到所有线程都到达该屏障点,然后所有线程才会继续执行。
CyclicBarrier
有一个计数器,在创建时需指定参与等待的线程数量。当一个线程调用 await()
方法,它就会被阻塞,直到所有线程都调用了 await()
方法,此时计数器归 0,所有被阻塞的线程会同时被释放继续执行。而且,CyclicBarrier
可以被重复使用,即一轮同步完成后,它可以重新开始下一轮同步。
CyclicBarrier与CountDownLatch的区别
1. 可重用性
- CyclicBarrier:具有可重用性,在一轮同步完成后,计数器会重置,能开启下一轮同步。
- CountDownLatch:不可重用,计数器一旦减到 0,就无法再恢复初始值,不能进行新一轮的等待。
2. 侧重点
- CyclicBarrier:强调的是多个线程之间相互等待,所有线程到达屏障点后才一起继续执行,更注重线程之间的协作。
- CountDownLatch:侧重于一个或多个线程等待其他线程完成操作,是单向的等待。
3. 计数器操作方式
- CyclicBarrier:每个线程调用
await()
方法时,计数器会自动减 1,直到为 0 时所有线程继续执行。 - CountDownLatch:需要在其他线程中手动调用
countDown()
方法来减少计数器的值。
4. 构造函数和功能
- CyclicBarrier:构造函数可以传入一个
Runnable
任务,当所有线程到达屏障点后,会先执行这个任务,然后再让所有线程继续执行。 - CountDownLatch:没有类似的功能。
使用场景
CyclicBarrier的使用场景
- 并行计算:在进行大规模数据处理时,可将数据分成多个部分,让多个线程并行处理,当所有线程完成各自部分的处理后,在
CyclicBarrier
处等待,全部完成后一起进行结果合并。 - 多玩家游戏:在多人在线游戏中,当所有玩家都准备好后,游戏才能开始。可以使用
CyclicBarrier
让所有玩家线程在准备好后在屏障处等待,等所有玩家都准备好后同时开始游戏。
CountDownLatch的使用场景
- 主线程等待子线程完成任务:比如主线程需要等待多个子线程完成数据加载、初始化等操作后,再进行后续处理。
- 并行任务启动:多个并行任务同时启动,主线程等待所有任务都启动完成后再进行下一步操作。
以下是一个 CyclicBarrier
的简单示例代码:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
int threadCount = 3;
// 创建 CyclicBarrier 对象,指定线程数量和所有线程到达屏障后执行的任务
CyclicBarrier barrier = new CyclicBarrier(threadCount, () -> {
System.out.println("All threads have reached the barrier.");
});
for (int i = 0; i < threadCount; i++) {
final int threadId = i;
new Thread(() -> {
try {
System.out.println("Thread " + threadId + " is working...");
// 模拟线程工作
Thread.sleep((long) (Math.random() * 1000));
System.out.println("Thread " + threadId + " has reached the barrier.");
// 线程到达屏障点,等待其他线程
barrier.await();
System.out.println("Thread " + threadId + " continues after the barrier.");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
在这个示例中,创建了一个 CyclicBarrier
对象,指定有 3 个线程参与同步,并传入一个 Runnable
任务。每个线程模拟执行任务,然后调用 await()
方法在屏障处等待,当所有线程都到达屏障点后,会先执行传入的 Runnable
任务,然后所有线程继续执行后续代码。