1、CyclicBarrier 的作用
一种同步辅助,允许一组线程彼此等待到达一个共同的障碍点。cyclicbarrier在包含固定大小的线程的程序中非常有用,这些线程有时必须彼此等待。这个屏障被称为循环,因为它可以在释放等待的线程之后重用。
2、核心结构
// 使用ReentrantLock加锁
private final ReentrantLock lock = new ReentrantLock();
// 锁条件变量,用来处理锁等待,锁唤醒
private final Condition trip = lock.newCondition();
// 初始化等待工作(屏障)的数量
private final int parties;
// 构造函数如果设置Runnable,则会触发Runnable方法
private final Runnable barrierCommand;
// 用于控制屏障的循环使用,如果 generation.token 为true,表示这个屏障已损坏
private Generation generation = new Generation();
// 正在等待的工作(屏障)的数量
private int count;
3、两个构造函数
// parties等待工作(屏障)的数量
public CyclicBarrier(int parties) {
this(parties, null);
}
// parties等待工作(屏障)的数量
// Runnable表示任务会在所有线程到达屏障后执行
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0)
throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
4、等待方法
// 等待直到所有方都调用了这个屏障。
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
/**
* 主要屏障代码,涵盖各种策略。
* 每当线程执行await,内部变量count--
* 如果count!=0,自旋在锁条件变量trip上等待
* 如果count==0,唤醒所有等待线程,如果初始化加载Runnable,那么执行这个方法,并开始
*/
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count;
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
5、屏障循环使用
// 更新屏障状态并唤醒所有人。
private void nextGeneration() {
// 唤醒上一代的所有等待线程
trip.signalAll();
// 设置新的控制屏障
count = parties;
generation = new Generation();
}
6、实例测试
有一组工作者需要完成一组工作。工作之前需要等待所有工作者全部准备好,准备好以后所有工作者开始工作。
/**
*
* CyclicBarrier用法实例
* 有一组工作者需要完成一组工作。工作之前需要等待所有工作者全部准备好,准备好以后所有工作者开始工作。
*
* @version 1.0
*/
public class CyclicBarrierDriverDemo {
public static void main(String[] args) {
Integer N = 5;
Runnable barrierAction = new Runnable() {
public void run() {
System.out.println("工作者全部准备好了,可以开始工作了。");
}
};
CyclicBarrier cyclicBarrier = new CyclicBarrier(N, barrierAction);
for (int i = 0; i < N; i++) {
new CyclicBarrierWorker(cyclicBarrier, i).start();
}
}
}
class CyclicBarrierWorker extends Thread {
CyclicBarrier barrier;
private Integer i;
public CyclicBarrierWorker(CyclicBarrier barrier, Integer i) {
this.barrier = barrier;
this.i = i;
}
public void run() {
try {
Random random = new Random();
Integer prepare = random.nextInt(1000);
Thread.sleep(prepare);
System.out.println("工作者" + i + "准备好了,准备时间 " + prepare + " 毫秒。");
barrier.await();
Integer work = random.nextInt(1000);
Thread.sleep(work);
System.out.println("工作者" + i + "工作完成,工作时间 " + work + " 毫秒。");
} catch (Exception e) {
}
}
}