CyclicBarrier是一个同步辅助类,它容许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 颇有用。由于该 barrier 在释放等待线程后能够重用,因此称它为循环 的 barrier。app
通俗点讲就是:让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,全部被屏障拦截的线程才会继续干活。ide
CyclicBarrier字面意思回环栅栏,经过它能够实现让一组线程等待至某个状态以后再所有同时执行。叫作回环是由于当全部等待线程都被释放之后,CyclicBarrier能够被重用。咱们暂且把这个状态就叫作barrier,函数
当调用await()方法以后,线程就处于barrier了。源码分析
先来个demo:spa
运行结果:线程
代码中设置了两个屏障点,第一个用于召集7个法师,等7个法师召集完后,在设置在一个屏障点,7位法师去寻找龙珠,而后召唤神龙,中间有个嵌套的关系!orm
源码分析对象
上述的例子,大体说了一下屏障,由于设置了两个屏障,并无演示上述说的可循环使用(Cyclic)的屏障(Barrier) 中的可循环使用(Cyclic)。ci
查看 CyclicBarrier.reset() 可知,可使 CyclicBarrier 回到最初始的状态,因为使用的相对较少,这里再也不演示。get
CyclicBarrier构造方法
能够看得出CyclicBarrier的内部是使用重入锁ReentrantLock和Condition。它有两个构造函数:
CyclicBarrier(int parties):建立一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预约义的操做。
CyclicBarrier(int parties, Runnable barrierAction) :建立一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操做,该操做由最后一个进入 barrier 的线程执行。
parties表示拦截线程的数量。
barrierAction 为CyclicBarrier接收的Runnable命令,用于在线程到达屏障时,优先执行barrierAction ,用于处理更加复杂的业务场景。
在CyclicBarrier中最重要的方法莫过于await()方法,在全部参与者都已经在此 barrier 上调用 await 方法以前,将一直等待。以下:
第二个参数0,说明不是超时等待
其实await()的处理逻辑仍是比较简单的:若是该线程不是到达的最后一个线程,则他会一直处于等待状态,除非发生如下状况:
最后一个线程到达,即index == 0
超出了指定时间(超时等待)
其余的某个线程中断当前线程
其余的某个线程中断另外一个等待的线程
其余的某个线程在等待barrier超时
其余的某个线程在此barrier调用reset()方法。reset()方法用于将屏障重置为初始状态。
在上面的源代码中,咱们可能须要注意Generation 对象,在上述代码中咱们老是能够看到抛出BrokenBarrierException异常,那么何时抛出异常呢?若是一个线程处于等待状态时,若是其余线程调用reset(),或者调用的barrier本来就是被损坏的,则抛出BrokenBarrierException异常。同时,任何线程在等待时被中断了,则其余全部线程都将抛出BrokenBarrierException异常,并将barrier置于损坏状态。
同时,Generation描述着CyclicBarrier的更显换代。在CyclicBarrier中,同一批线程属于同一代。当有parties个线程到达barrier,generation就会被更新换代。其中broken标识该当前CyclicBarrier是否已经处于中断状态。
默认barrier是没有损坏的。
当barrier损坏了或者有一个线程中断了,则经过breakBarrier()来终止全部的线程:
在breakBarrier()中除了将broken设置为true,还会调用signalAll将在CyclicBarrier处于等待状态的线程所有唤醒。
当全部线程都已经到达barrier处(index == 0),则会经过nextGeneration()进行更新换地操做,在这个步骤中,作了三件事:
唤醒全部线程
重置count
generation
CyclicBarrier同时也提供了await(long timeout, TimeUnit unit) 方法来作超时控制:
能够看出其内部仍是经过调用
private int dowait(boolean timed, long nanos)
实现的。
CyclicBarrier 和 CountDownLatch 的区别
CountDownLatch 的计数器只能使用一次。而 CyclicBarrier 的计数器可使用 reset() 方法重置。因此 CyclicBarrier 能处理更为复杂的业务场景,好比若是计算发生错误,能够重置计数器,并让线程们从新执行一次。
CyclicBarrier 还提供其余有用的方法,好比 getNumberWaiting 方法能够得到 CyclicBarrier 阻塞的线程数量。isBroken 方法用来知道阻塞的线程是否被中断。好比如下代码执行完以后会返回 true。
CountDownLatch 会阻塞主线程,CyclicBarrier 不会阻塞主线程,只会阻塞子线程。