CyclicBarrier是一个同步辅助工具类,它允许一组线程之间相互等待,直到到达某个公共屏障点 (common barrier point)。如果一个程序中有固定的线程数,并且线程之间需要相互等待,这时候CyclicBarrier是一个很好的选择。之所以叫它cyclic,是因为在释放等待线程之后,它可以被重用。
重要成员属性
//内部类
private static class Generation {
boolean broken = false;
}
/** The lock for guarding barrier entry */
//barrier入口锁
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
//Condition条件
private final Condition trip = lock.newCondition();
/** The number of parties */
//屏障线程的数量
private final int parties;
/* The command to run when tripped */
//线程达到command时,执行的barrierCommand
private final Runnable barrierCommand;
/** The current generation */
private Generation generation = new Generation();
/**
* Number of parties still waiting. Counts down from parties to 0
* on each generation. It is reset to parties on each new
* generation or when broken.
*/
//等待到达barrier的参与线程的数量
private int count;
CyclicBarrier中包含以下重要的成员变量:
- trip,等待条件,线程会在此条件上阻塞直到所有线程都到达barrier;
- parties,参与barrier的线程数量
- barrierCommand,所有线程到达barrier后执行的操作
- generation,当前generation,用于判断barrier是否终止
- count,等待到达barrier的数量。
构造函数
//构造函数
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
/**
* Creates a new {@code CyclicBarrier} that will trip when the
* given number of parties (threads) are waiting upon it, and
* does not perform a predefined action when the barrier is tripped.
*
* @param parties the number of threads that must invoke {@link #await}
* before the barrier is tripped
* @throws IllegalArgumentException if {@code parties} is less than 1
*/
//构造函数
public CyclicBarrier(int parties) {
this(parties, null);
}
CyclicBarrier的构造函数包括两个,其中parties表示参与的线程数量,另外一个参数表示所有线程到达barrier后执行的函数线程。
重要方法
//等待线程到达barrier,线程阻塞
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
//带超时await
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
//具体等待屏障的代码
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//当前的generation
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
//线程中断,终止barrier,唤醒所有线程
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count;//当前剩余未到达barrier的数量
if (index == 0) { // tripped,为0,所有都到达,执行command
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();//更新barrier状态并唤醒所有线程
return 0;
} finally {
//没有执行ranAction终止barrier,唤醒所有线程
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) {
//线程中断,当前的generation被销毁
if (g == generation && ! g.broken) {
breakBarrier();//终止barrier
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();//释放锁
}
}
/**
* Sets current barrier generation as broken and wakes up everyone.
* Called only while holding lock.
*/
//barrier中断并唤醒所有线程
private void breakBarrier() {
generation.broken = true;
count = parties;
//唤醒所有线程
trip.signalAll();
}
//更新barrier状态唤醒所有线程
private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
// set up next generation
count = parties;
generation = new Generation();
}
//重置barrier,就是终止barrier,并设置新的generation
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
breakBarrier(); // break the current generation
nextGeneration(); // start a new generation
} finally {
lock.unlock();
}
}
CyclicBarrier有两个重要方法一个await方法,await方法的主要流程如下:
- 首先判断当前generation是否中断,如中断,抛出异常
- 判断线程是否中断,线程中断,终止barrier,抛出异常
- 判断未到达barrier的线程数是否为0,如果为0,说名全部到达,调用barrierCommand的run方法执行命令(如果存在);
- 更新barrier状态并唤醒所有线程。
CyclicBarrier令一个重要方法是reset方法,它可以重置barrier状态,从而开始新的barrier;
CyclicBarrier和CountDownLatch的区别
- CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。
- CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。