type
status
date
slug
summary
tags
category
icon
password
原文
CyclicBarrier(循环屏障)是 Java 并发包中的同步工具,用于让一组线程到达某个屏障点后再同时继续执行。与 CountDownLatch 不同,CyclicBarrier 可以重复使用(“循环” 特性),适合需要多轮协作的场景(如多阶段任务,每阶段需所有线程准备就绪后再开始)。工作流程

工作线程调用 await 方法,首先需要竞争到锁。
拿到锁的线程,会先扣减 CyclicBarrier 的 count。count 经过扣减 >0 ,当前线程则会进入 Condition 中的队列中并且释放锁和进入阻塞状态(WAITTING),等待唤醒。
未能拿到锁的线程则会进入 Sync 队列,等待唤醒竞争锁。
假设 count 递减后为 0,说明所有线程都已到达屏障,唤醒所有在Condition 队列中的线程。
并且重置计数器和generation,表示本轮结束,开启下一次的屏障
核心方法
构造器
- CyclicBarrier(int parties)
parties为线程数
- CyclicBarrier(int parties, Runnable barrierAction)
barrierAction由最后一个线程到达时触发该 Runnable 运行
await
线程调用后会进入阻塞状态,直到所有线程到达屏障会被破坏
返回值为 线程的序号即第几个到达的
- int await() 无限期等待
- int await(long timeout, TimeUnit unit) 限时等待,超时后会被破坏屏障
源码解析
重要属性
count 为本轮的线程计数器。count在初始化和重置时等同于parties
parties 为参与的线程数。
Condition 条件队列,假设线程调用 await 成功,则线程进入该条件队列
Generation:
Generation是实现循环CyclicBarrier的核心类。
一轮结束会重新创建Generation对象
await
首先线程需要拿到锁,进行计数器的扣减。使用了ReentrantLock,扣减这一部分代码就无需使用自旋+CAS 操作。
(1) index=0,表示当前线程是最后一个到达屏障的线程。如果构造器使用的是带Runnable的,先执行该线程。
index=0 也表示本轮的线程任务都已结束,需要开启下一轮的循环。需要重置计数器等动作。
(2) 如果不是最后一个到达的线程就会进入自旋。
如果工作线程未出现异常,那么这个线程则会进入到 Condition中的队列,也就是在(3)处执行,当然当前线程需要释放锁,然后进入阻塞状态(WAITTING),到这里一个线程的 await 方法就结束了。
自旋的逻辑是保证线程在一定时间内,可以进入阻塞状态。
重置
当最后一个线程到达时,需要重置计数器,generation,以及唤醒所有在Condition 队列中的所有线程。这样才能进入下一轮的循环中。
generation 对象主要是用来维护本次循环的信息的。
- 它内部维护了一个broken属性(布尔值),如果为 true 则表示本轮循环已被破坏。
- 可以用来判断是否处于本轮中。
- Author:newrain-zh
- URL:https://alex.sh.cn/article/CyclicBarrier
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!


