CyclicBarrier
是Java并发包java.util.concurrent
中提供的一个同步辅助类,它允许一组线程相互等待,直到到达某个公共屏障点(common barrier point)后再继续执行。CyclicBarrier
之所以被称为“循环”的,是因为一旦所有参与线程到达了屏障点,这个屏障就可以被重用。
CyclicBarrier的基本原理:
- 构造:
-
CyclicBarrier(int parties)
:创建一个CyclicBarrier
实例,参数parties
定义了参与屏障同步的线程数。CyclicBarrier(int parties, Runnable barrierAction)
:除了定义线程数外,还可以传入一个Runnable
,当所有线程到达屏障时,这个Runnable
会被其中一个线程执行。
- 使用:
-
- 每个线程在到达某个点时调用
await()
方法,这会使线程进入等待状态,直到所有参与线程都调用了await()
。 - 当所有线程都到达屏障点后,它们会被释放并继续执行。
- 如果某个线程在等待过程中被中断,或者有线程抛出了
BrokenBarrierException
或TimeoutException
,则整个屏障被破坏,所有等待的线程将被释放并抛出异常。
- 每个线程在到达某个点时调用
CyclicBarrier的使用示例:
下面是一个使用CyclicBarrier
的示例代码,模拟了一个场景,其中多个线程需要同时启动一个计算任务,只有当所有线程都准备好了,计算才会开始。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
final int numberOfThreads = 5;
CyclicBarrier barrier = new CyclicBarrier(numberOfThreads, () -> {
System.out.println("所有线程已准备好,开始计算...");
});
for (int i = 0; i < numberOfThreads; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 正在准备...");
Thread.sleep((long) (Math.random() * 1000)); // 模拟准备时间
System.out.println(Thread.currentThread().getName() + " 准备完毕,等待其他线程...");
barrier.await(); // 等待所有线程到达屏障
System.out.println(Thread.currentThread().getName() + " 继续执行...");
} catch (InterruptedException | BrokenBarrierException e) {
Thread.currentThread().interrupt();
System.err.println("线程中断:" + e.getMessage());
}
}).start();
}
}
}
在这个例子中,我们创建了一个CyclicBarrier
实例,指定有5个线程参与。当所有5个线程都调用了await()
方法时,屏障被触发,此时传递给CyclicBarrier
构造函数的Runnable
被调用,打印出所有线程已准备好的消息,随后所有线程继续执行。
注意事项:
- 如果线程在等待过程中被中断,那么它会抛出
InterruptedException
。 - 如果一个线程在
await()
方法中抛出了异常(除了InterruptedException
),那么屏障将被破坏,其他所有等待的线程将会接收到BrokenBarrierException
。 CyclicBarrier
可以重用,当所有线程都通过了一个屏障点后,它会自动重置,可以再次被所有线程使用。但是,如果屏障被破坏,需要重新创建一个新的CyclicBarrier
实例。