CyclicBarrier
唤醒的两种逻辑:
-
创建新的一代 newGeneration 时会唤醒所有线程 signalAll
-
打破当前代 将broken修改为true时 会唤醒所有线程 signalAll 但是这种会抛出Broken异常
tips: 怎么才会打破当前代?就是当前线程给中断抛出异常时,就会去调用brokenBarrier方法打破当前代
CyclicBarrier里面有个变量broken,当broken为true时,表示当前‘代’被打破,来到这个代的线程会抛出BrokenException异常,
而在这个代被挂起的线程,都会被唤醒并且抛出BrokenException异常
await()方法
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);//false表示不支持超时机制
} 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;
//加锁的原因:下面需要用到condition
lock.lock();
try {
final Generation g = generation;
/**/异常逻辑
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
**/
//调用一次await方法就会减一次count,直到最后一个线程‘上车’就发车
int index = --count;
//说明人到齐了,准备发车
if (index == 0) { // tripped
boolean ranAction = false;
try {
//这个是表示最后一个线程到达需要完成的动作
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
//开启新的一代,唤醒所有给挂起的线程
/**{1.唤醒所有线程
2.重置count
3.开启新的一代
}**/
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
//如果当前线程不是最后一个线程的话,就走下面自旋的逻辑
for (;;) {
try {
if (!timed)
//如果不是支持超时等待的话,就走condition的await()逻辑,会释放锁,加入条件队列尾部,挂起自己等待被唤醒
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();
}
}
//执行到这里,1.最后一个线程开启了新的一代,唤醒了所有线程
//2.gengration被打破,异常唤醒
//3.当前线程支持超时机制,并且超时了,被加入阻塞队列,然后拿到锁了给唤醒了
//这个是 2 那种情况
if (g.broken)
throw new BrokenBarrierException();
//这里是 1 那种情况
if (g != generation)
return index;
//这里是 3 那种情况
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
正常唤醒逻辑:nextGeneration()
private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
count = parties;
generation = new Generation();
}
异常唤醒逻辑:breakGeneration()
private void breakBarrier() {
//将代中的broken设置为true,表示这一代是被打破了的,再来到这一代的线程,直接抛出异常.
generation.broken = true;
//重置count为parties
count = parties;
//将在trip条件队列内挂起的线程 全部唤醒,唤醒后的线程 会检查当前代 是否是打破的,
//如果是打破的话,接下来的逻辑和 开启下一代 唤醒的逻辑不一样.
trip.signalAll();
}