用法
- cyclic 循环的
- barrier 屏障
字面意思理解就是循环的屏障,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier 可以被重用。CountDownLatch 可以实现类似的功能,但是 CountDownLatch 不可重复使用。
import java.util.concurrent.CyclicBarrier;
public class TestCyclicBarrier {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(20, () -> System.out.println("满人,发车,突突突"));
for (int i = 0;i<100;i++){
new Thread(()->{
try {
cyclicBarrier.await();
} catch (Exception ignore) {
}
}).start();
}
}
}
输出:
满人,发车,突突突
满人,发车,突突突
满人,发车,突突突
满人,发车,突突突
满人,发车,突突突
核心源码
CyclicBarrier 底层通过 [[ReentrantLock]] 和一个条件变量来实现。
核心变量和构造方法
private final ReentrantLock lock = new ReentrantLock();
// 条件队列
private final Condition trip = lock.newCondition();
// 需要到达屏障的线程数
private final int parties;
// 还未到达屏障的线程数
private int count;
// parties 个线程到达屏障后,执行的回调方法
private final Runnable barrierCommand;
// 每次复用 CyclicBarrier 时,创建新的 Generation
private Generation generation = new Generation();
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
await
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
dowait
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) // command.run() 抛出异常
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) { // generation 未改变,屏障未终止
breakBarrier(); // 终止屏障
throw ie; // 抛出中断异常
} else { // generation 已改变或者屏障已终止
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();
}
}
reset 复用屏障
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
breakBarrier(); // break the current generation
nextGeneration(); // start a new generation
} finally {
lock.unlock();
}
}
breakBarrier 终止屏障
- 设置 broken 标志位
- 重置 count 为 parties
- 调用 AQS 中 ConditionObject 的 signalAll
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
nextGeneration 开启新一轮屏障
- 唤醒所有等待线程
- 复位 count
- 生成新的 Generation
private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
// set up next generation
count = parties;
generation = new Generation(); // 生成新的 Generation,复用 CyclicBarrier
}