线程分别拿到当前锁,最先获得锁的N-1个线程,调用条件锁Condition的await方法,根据前面条件锁的源码分析我们知道,调用条件锁的await方法会释放当前锁,然后再调用Unsafa类底层 park 阻塞线程。
当最后一个线程调用await方法时(也就是上面的 if (index == 0) 分支逻辑,count减为0,屏障打破),会执行命令线程(构造方法的第二个入参Runnable),然后调用nextGeneration方法,唤醒所有的条件锁等待的N-1个线程(唤醒并不一定马上执行),然后重置计数与当前代,也就是一个新的屏障了,这也就是为什么可以重复使用的原因。
最后一个线程释放锁,N-1线程中的线程陆续获得锁,释放锁,完成整个流程
CyclicBarrier 总结支持两个构造参数:线程数和需要执行的命令线程
CyclicBarrier 是基于ReentrantLock和Condition来实现屏障逻辑的
先抢到锁的N-1个线程会调用条件锁的await方法从而被阻塞
最后一个获得锁的线程来唤醒之前的N-1个线程以及来调用命令线程的run方法
最后一个获得锁的线程会生成一个新的屏障(new Generation()),也就是可以重复使用的屏障
如果线程中有一个线程被中断,整个屏障被破坏后,所有线程都可能抛出BrokenBarrierException异常
原文首发地址:https://jinglingwang.cn/archives/cyclicbarrier
CyclicBarrier 与CountDownLatch的区别CyclicBarrier 是基于重入锁和条件锁来实现的
CountDownLatch 是基于AQS的同步功能来实现的
CyclicBarrier 不允许0个线程,会抛出异常
CountDownLatch 允许0个线程,虽然没什么*用
CyclicBarrier 阻塞的是N-1个线程,需要每个线程调用await,之后由最后一个线程来唤醒所有的等待线程,这也就是屏障的意思
CountDownLatch 是计数为N,阻塞的不一定是N个线程(可以是一个或多个),由线程显示调用countDown方法来减计数,计数为0时,唤醒阻塞的一个线程或多个线程
CyclicBarrier 最后一个线程会重置屏障的参数,生成一个新的Generation,可以重复使用,不需要重新new CyclicBarrier
CountDownLatch 没有重置计数的地方,计数为0后不可以重复使用,需要重新new CountDownLatch 才可以再次使用