CyclicBarrier源码理解

唤醒的两种逻辑:
创建新的一代时会唤醒所有线程
打破当前代 将修改为true时 会唤醒所有线程但是这种会抛出异常

CyclicBarrier源码理解

文章插图
tips: 怎么才会打破当前代?就是当前线程给中断抛出异常时,就会去调用方法打破当前代
里面有个变量,当为true时,表示当前‘代’被打破,来到这个代的线程会抛出异常,
【CyclicBarrier源码理解】而在这个代被挂起的线程,都会被唤醒并且抛出异常
await()方法
public int await() throws InterruptedException, BrokenBarrierException {try {return dowait(false, 0L);//false表示不支持超时机制} catch (TimeoutException toe) {throw new Error(toe); // cannot happen}}
()
private int dowait(boolean timed, long nanos)throws InterruptedException, BrokenBarrierException,TimeoutException {final ReentrantLock lock = this.lock;//加锁的原因:下面需要用到conditionlock.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) {// trippedboolean ranAction = false;try {//这个是表示最后一个线程到达需要完成的动作final Runnable command = barrierCommand;if (command != null)command.run();ranAction = true;//开启新的一代,唤醒所有给挂起的线程/**{1.唤醒所有线程2.重置count3.开启新的一代}**/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();}}
正常唤醒逻辑:()
private void nextGeneration() {// signal completion of last generationtrip.signalAll();count = parties;generation = new Generation();}
异常唤醒逻辑:()
private void breakBarrier() {//将代中的broken设置为true,表示这一代是被打破了的,再来到这一代的线程,直接抛出异常.generation.broken = true;//重置count为partiescount = parties;//将在trip条件队列内挂起的线程 全部唤醒,唤醒后的线程 会检查当前代 是否是打破的,//如果是打破的话,接下来的逻辑和 开启下一代 唤醒的逻辑不一样.trip.signalAll();}