成员变量
java
// 独占可重入锁,所有操作加锁保证线程安全
private final ReentrantLock lock = new ReentrantLock();
// 条件变量,所有到达栅栏的线程阻塞在此
private final Condition trip = lock.newCondition();
// 总等待线程数(固定不变,final)
private final int parties;
// 最后一个线程到达时执行的回调任务
private final Runnable barrierCommand;
// 当前代次实例
private Generation generation = new Generation();
// 当前剩余等待线程数(每轮从parties递减到0)
private int count;
构造方法
java
// 带屏障任务
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
// 无屏障任务,委托上面构造器
public CyclicBarrier(int parties) {
this(parties, null);
}
Generation
java
private static class Generation {
boolean broken = false; // true=本轮栅栏损坏
}
await
java
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // timed=false不会触发超时,不可能走到这里
}
}
dowait
java
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();
}
// 等待计数-1,index是当前线程到达序号(最后一个为0)
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 {
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
// 代次更新,说明本次 count 已经为 0,栅栏放行,返回序号
return index;
if (timed && nanos <= 0L) {
// 超时未集齐线程,破坏栅栏抛超时异常
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
nextGeneration
java
private void nextGeneration() {
// 1. 唤醒当前代所有阻塞在trip条件队列的线程
trip.signalAll();
// 2. 重置等待计数器为初始总线程数
count = parties;
// 3. 新建Generation实例,切换到全新一代,旧代作废
generation = new Generation();
}
breakBarrier
java
private void breakBarrier() {
// 1. 标记当前代栅栏损坏
generation.broken = true;
// 2. 重置计数器
count = parties;
// 3. 唤醒所有等待线程
trip.signalAll();
}
总结
plaintext
线程调用 barrier.await()
↓
dowait(timed=false, nanos=0)
↓
lock.lock() → 抢占独占锁
↓
读取当前代 Generation g = generation
├─ if g.broken → 抛 BrokenBarrierException,finally释放锁
└─ 校验当前线程是否中断 Thread.interrupted()
├─ 是 → breakBarrier() + 抛 InterruptedException,释放锁
└─ 否 → count = count - 1,得到当前index
├─────────────────────┬
↓ ↓
index == 0(最后线程) index != 0(普通等待线程)
↓ ↓
执行 barrierCommand 进入 for(;;) 循环阻塞
│ │
│ │→ trip.await()
│ │
│ ↓(被signalAll唤醒后)重新竞争lock锁
│ │
│ ├─ g != generation → 正常return index
↓
任务执行成功 → nextGeneration()
│ ↓
│ trip.signalAll() 唤醒所有条件队列线程
│ count重置为parties
│ new Generation() 切换代次
↓
finally 释放锁 lock.unlock()