Lazy loaded image
🗒️CyclicBarrier jdk8 源码分析
Words 1750Read Time 5 min
2025-10-21
2025-11-13
type
status
date
slug
summary
tags
category
icon
password
原文
CyclicBarrier(循环屏障)是 Java 并发包中的同步工具,用于让一组线程到达某个屏障点后再同时继续执行。与 CountDownLatch 不同,CyclicBarrier 可以重复使用(“循环” 特性),适合需要多轮协作的场景(如多阶段任务,每阶段需所有线程准备就绪后再开始)。
 
 

工作流程

notion image
工作线程调用 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 则表示本轮循环已被破坏。
  • 可以用来判断是否处于本轮中。
 
 
上一篇
JDK线程池源码分析
下一篇
CountDownLatch jdk8 源码分析

Comments
Loading...