悠悠楠杉
如何在Java中使用CyclicBarrier协调线程,java线程协同
在Java的并发编程世界中,线程之间的协调是一个关键课题。当多个线程需要协同完成某项任务,并且必须在某个“检查点”上彼此等待时,CyclicBarrier便成为了一个强大而灵活的工具。它不像CountDownLatch那样只能使用一次,而是支持重复使用的屏障机制,非常适合用于周期性同步场景。
CyclicBarrier直译为“循环屏障”,顾名思义,它允许一组线程相互等待,直到所有线程都到达一个公共的屏障点(barrier point),然后才一起继续执行。这种机制在模拟并行计算、测试性能、分阶段任务处理等场景中非常实用。
我们先来看一个简单的例子。假设我们要模拟一场赛跑比赛,有5位运动员(即5个线程),比赛开始前所有人都必须站在起跑线上。只有当所有运动员准备就绪后,裁判才会鸣枪发令。这时,CyclicBarrier就能完美地扮演“裁判”的角色。
java
import java.util.concurrent.CyclicBarrier;
public class RaceExample {
public static void main(String[] args) {
int numberOfRunners = 5;
CyclicBarrier barrier = new CyclicBarrier(numberOfRunners,
() -> System.out.println("所有运动员已就位,比赛开始!"));
for (int i = 1; i <= numberOfRunners; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 正在准备...");
Thread.sleep((long)(Math.random() * 3000)); // 模拟准备时间
System.out.println(Thread.currentThread().getName() + " 已就位,等待发令");
barrier.await(); // 等待其他线程
System.out.println(Thread.currentThread().getName() + " 冲刺!");
} catch (Exception e) {
e.printStackTrace();
}
}, "Runner-" + i).start();
}
}
}
在这个例子中,我们创建了一个容量为5的CyclicBarrier,并传入一个Runnable作为“屏障动作”——也就是当所有线程都调用await()后自动执行的任务。每个线程在准备完成后调用barrier.await(),一旦5个线程全部到达,屏障被触发,所有线程同时解除阻塞,继续执行后续逻辑。
与CountDownLatch相比,CyclicBarrier的最大优势在于它的“可重用性”。一旦所有线程通过屏障,计数器会自动重置,可以再次用于下一轮同步。这使得它特别适合用于循环或分阶段的任务,比如每轮数据处理完成后进行汇总分析。
考虑一个更复杂的场景:一个科学计算程序需要将一个大数组分成若干块,由多个线程并行处理。每轮迭代后,所有线程必须等待彼此完成当前阶段的计算,然后才能进入下一阶段。这种情况下,CyclicBarrier可以确保各线程步调一致。
java
double[] data = new double[1000];
CyclicBarrier barrier = new CyclicBarrier(4, () -> {
System.out.println("所有线程完成本轮计算,进入下一阶段");
});
for (int i = 0; i < 4; i++) {
final int threadId = i;
new Thread(() -> {
for (int round = 0; round < 3; round++) {
// 模拟分段计算
int start = threadId * 250;
int end = start + 250;
for (int j = start; j < end; j++) {
data[j] = Math.sin(data[j] + round);
}
try {
barrier.await(); // 等待其他线程完成本轮
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
值得注意的是,CyclicBarrier在遇到线程中断或超时异常时会进入“破损状态”(broken),此时所有等待的线程都会抛出BrokenBarrierException。可以通过调用isBroken()方法检测状态,或使用reset()方法手动重置屏障。
此外,await()方法还支持设置超时时间,避免无限等待:
java
try {
barrier.await(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
System.out.println("等待超时,部分线程未及时到达");
}
总之,CyclicBarrier是Java并发工具包中一个设计精巧、用途广泛的同步辅助类。它让多线程协作变得更加直观和可控,尤其适用于需要阶段性同步的并行任务。只要合理设计屏障点和回调逻辑,就能有效提升程序的并发效率与稳定性。

