CyclicBarrier是java.util.concurrent包下面的一个工具类,字面意思是可循环使用(Cyclic)的屏障(Barrier),通过它可以实现让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,所有被屏障拦截的线程才会继续执行。
讲解CyclicBarrier之前先说明CyclicBarrier能解决的实际问题,和CountDownLatch区别
CountDownLatch | CyclicBarrier |
---|---|
计数为0时,无法重置 | 计数达到0时,计数置为传入的值重新开始 |
调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响 | 调用await()方法计数减一,若减一后的值不等于0,则线程阻塞 |
不可重复使用 | 可重复使用 |
很显然CyclicBarrier作用主要是计数的可重复使用,比如游戏房间需要在个人进入才可以开始游戏,可能会有三个屏障,1.进入游戏 2.选择角色 3.加载游戏 这三个屏障都需要房间内的玩家都完成上一步之后才可以进行下一步. 类似这种需求就非常适合CyclicBarrier进行处理
CyclicBarrier构造方法:
// parties表示线程数,即游戏中的人数 barrierAction表示越过屏障之后所要执行的任务 public CyclicBarrier(int parties, Runnable barrierAction) {
// 没有任务的构造 public CyclicBarrier(int parties) { |
CyclicBarrier内置属性
// 通过ReentrantLock(可重入锁)实现同步,同步实现机制可先了解一下AQS (AbstractQueuedSynchronizer) private final ReentrantLock lock = new ReentrantLock(); // Condition 通过Condition实现线程等待,线程通信 // 栅栏数量 (游戏房间内的人数) // 越过屏障之后需要执行的任务 // 设置屏障状态 如果运行中出现故障则状态broken设置为true 然后重置barrier // 当前某个屏障之前剩余的等待数量 |
CyclicBarrier的核心方法为dowait方法,下面对该方法进行详解
dowait 方法为private 方法通过await方法进行调用,两个方式只是设置超时等待的区别
public int await() throws InterruptedException, BrokenBarrierException {
public int await(long timeout, TimeUnit unit) //把超时时间转换为纳秒单位 |
//timed 是否有设置超时 nanos 纳秒数 private int dowait(boolean timed, long nanos) if (g.broken) if (Thread.interrupted()) { //每执行一次dowait 维护的当前的count数量– 如果等于0 表示所有线程都准备完毕, 可以进行下一步 int index = –count; // 判断barrier 是否有任务 // 重置barrier 进行下一步 // 如果任务没有执行成功,则设置broken // 循环等待 直到唤醒 故障 中断 或者超时 if (g.broken) if (g != generation) if (timed && nanos <= 0L) { |
DEMO