CyclicBarrier
循环的栅栏。使用上,与CountDownLatch
类似,也不太一样。这两个类都是用来解决线程同步问题的。同步问题说的通俗一点就是线程间通信。
CountDownLatch
,是主线程等待所有子线程结束任务
CyclicBarrier
,是多个子线程互相等待
下面看看CyclicBarrier
的源码实现
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;// 需要汇集的线程的个数,是一个不变量。用来做重置
this.count = parties;// 需要汇集的线程的个数,用来做计数
this.barrierCommand = barrierAction;// 线程汇集到一点后的回调异步任务
}
// parties,需要汇集的线程的个数
public CyclicBarrier(int parties) {
this(parties, null);
}
两种构造方式,一种是带有Runnable
回调的,一种没有。带有回调是指当多个子线程汇集到一点后,可以执行一个异步任务,后面会分析到。
private static class Generation {
boolean broken = false;// 栅栏是否被破坏的标识
}
private final ReentrantLock lock = new ReentrantLock();// 可重入锁,一定是可重入的。
private final Condition trip = lock.newCondition();// 条件等待期
private final int parties;// 需要汇集的线程的个数,是一个不变量。用来做重置
private final Runnable barrierCommand;// 线程汇集到一点后的回调异步任务
private Generation generation = new Generation();// 每个新的栅栏会new这么一个对象
private int count;// 需要汇集的线程的个数,用来做计数
上面是一堆成员变量,各自的用途已经在注释中写明。下面看跟API相关的几个方法。await
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
无论是限时等待还是不限时等待,都会去调用dowait
方法。重点在这个dowait
方法。
private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();// 线程进来先上锁,所以这边用的一定是可重入锁
try {
final Generation g = generation;// 把generation暂时保存一下,后面比对用
if (g.broken)// 如果栅栏已经被破坏,则抛出已经被破坏的异常
throw new BrokenBarrierException();
if (Thread.interrupted()) {// 如果检测到当前线程被打断,则把整个栅栏都通知破坏了。因为其他线程再等待也等不来。
breakBarrier();
throw new InterruptedException();
}
int index = --count;// 来一个线程,计数器-1
if (index == 0) { // 如果计数器减到0,说明所有线程都汇集到某一点了。
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 {// 其他线程破坏了栅栏
Thread.currentThread().interrupt();// 自我中断
}
}
if (g.broken)// 再看看栅栏是否被破坏
throw new BrokenBarrierException();
if (g != generation)// 如果generation刷新说明成功了。返回即可
return index;
if (timed && nanos <= 0L) {// 超时情况,破坏栅栏
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}