CyclicBarrier的await()方法底层原理
一、定义
CyclicBarrier 的 await() 方法是其核心功能之一,用于让线程在屏障点等待,直到所有参与的线程都到达屏障后,才能继续执行。
其底层实现依赖于 AQS(AbstractQueuedSynchronizer) 和 ReentrantLock,以下是 await() 方法的底层原理的详细解析
二、CyclicBarrier 的核心依赖
CyclicBarrier 的底层实现基于以下两个核心组件:
1、ReentrantLock:
- 用于保护共享资源的访问,确保线程安全
2、Condition:
- 用于线程的等待和唤醒。
CyclicBarrier 内部维护了一个计数器(count),表示尚未到达屏障的线程数。当计数器减至 0 时,屏障被触发,所有等待的线程被唤醒。
三、await() 方法的工作流程
当线程调用 await() 方法时,底层逻辑如下:
(1) 检查屏障是否已破坏
如果屏障已被破坏(如调用了 reset() 或线程被中断),则抛出 BrokenBarrierException
(2) 减少计数器
使用 ReentrantLock 加锁,确保线程安全。
将计数器 count 减 1。
如果 count 减至 0,表示所有线程都已到达屏障,执行以下操作:
a、执行预定义的 Runnable 任务(如果有)。
b、唤醒所有等待的线程。
c、重置计数器为初始值(parties),以便屏障可以重复使用。
(3) 线程等待
如果 count 未减至 0,线程调用 Condition.await() 进入等待状态。
线程被挂起,直到以下条件之一满足:
a、其他线程调用 await() 将 count 减至 0,触发屏障。
b、线程被中断(抛出 InterruptedException)
c、屏障被破坏(抛出 BrokenBarrierException)
(4) 返回线程到达屏障的顺序索引
- 当线程被唤醒后,await() 方法返回一个整数,表示线程到达屏障的顺序索引(从 0 到 parties-1)
四、以下是 await() 方法的简化代码逻辑
1、CyclicBarrier.await()

2、CyclicBarrier.dowait()
// timed:表示当前调用await方法的线程是否指定了超时时长,如果 true 表示线程是响应超时的
// nanos:线程等待超时时长,单位是纳秒
private int dowait(boolean timed, long nanos) {
final ReentrantLock lock = this.lock;
// 加锁
lock.lock();
try {
// 获取当前代
final Generation g = generation;
// 【如果当前代是已经被打破状态,则当前调用await方法的线程,直接抛出Broken异常】
if (g.broken)
throw new BrokenBarrierException();
// 如果当前线程被中断了,则打破当前代,然后当前线程抛出中断异常
if (Thread.interrupted()) {
// 设置当前代的状态为 broken 状态,唤醒在 trip 条件队列内的线程
breakBarrier();
throw new InterruptedException();
}
// 逻辑到这说明,当前线程中断状态是 false, 当前代的 broken 为 false(未打破状态)
// 假设 parties 给的是 5,那么index对应的值为 4,3,2,1,0
int index = --count;
// 条件成立说明当前线程是最后一个到达 barrier 的线程,【需要开启新代,唤醒阻塞线程】
if (index == 0) {
// 栅栏任务启动标记
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
// 启动触发的任务
command.run();
// run()未抛出异常的话,启动标记设置为 true
ranAction = true;
// 重置屏障,这里会【唤醒所有的阻塞队列】
nextGeneration();
// 返回 0 因为当前线程是此代最后一个到达的线程,index == 0
return 0;
} finally {
// 如果 command.run() 执行抛出异常的话,会进入到这里
if (!ranAction)
breakBarrier();
}
}
// 自旋,一直到条件满足、当前代被打破、线程被中断,等待超时
for (;;) {
try {
// 根据是否需要超时等待选择阻塞方法
if (!timed)
// 当前线程释放掉 lock,【进入到 trip 条件队列的尾部挂起自己】,等待被唤醒
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
// 被中断后来到这里的逻辑
// 当前代没有变化并且没有被打破
if (g == generation && !g.broken) {
// 打破屏障
breakBarrier();
// node 节点在【条件队列】内收到中断信号时 会抛出中断异常
throw ie;
} else {
// 等待过程中代变化了,完成一次自我打断
Thread.currentThread().interrupt();
}
}
// 唤醒后的线程,【判断当前代已经被打破,线程唤醒后依次抛出 BrokenBarrier 异常】
if (g.broken)
throw new BrokenBarrierException();
// 当前线程挂起期间,最后一个线程到位了,然后触发了开启新的一代的逻辑
if (g != generation)
return index;
// 当前线程 trip 中等待超时,然后主动转移到阻塞队列
if (timed && nanos <= 0L) {
breakBarrier();
// 抛出超时异常
throw new TimeoutException();
}
}
} finally {
// 解锁
lock.unlock();
}
}
3、CyclicBarrier.nextGeneration()

4、CyclicBarrier.breakBarrier()

五、动态过程文字描述
假设 CyclicBarrier 的参与线程数为 3,以下是线程并发操作的动态过程:
1、初始状态:
- count = 3,屏障未破坏,CLH 队列为空
2、线程 T1 调用 await():
- count 减至 2,T1 进入等待状态

3、线程 T2 调用 await():
- count 减至 1,T2 进入等待状态。

4、线程 T3 调用 await():
count 减至 0,屏障被触发。
执行回调任务,唤醒 T1 和 T2。
重置计数器为 3,屏障进入下一轮使用。

CyclicBarrier的await()方法底层原理的更多相关文章
- KVO-基本使用方法-底层原理探究-自定义KVO-对容器类的监听
书读百变,其义自见! 将KVO形式以代码实现呈现,通俗易懂,更容易掌握 :GitHub -链接如果失效请自动搜索:https://github.com/henusjj/KVO_base 代码中有详 ...
- synchronized底层原理
synchronized底层语义原理 Java 虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现. 在 Java 语言中,同步用的最多的地方可能是被 syn ...
- HashMap底层原理分析(put、get方法)
1.HashMap底层原理分析(put.get方法) HashMap底层是通过数组加链表的结构来实现的.HashMap通过计算key的hashCode来计算hash值,只要hashCode一样,那ha ...
- 红黑树规则,TreeSet原理,HashSet特点,什么是哈希值,HashSet底层原理,Map集合特点,Map集合遍历方法
==学习目标== 1.能够了解红黑树 2.能够掌握HashSet集合的特点以及使用(特点以及使用,哈希表数据结构) 3.能够掌握Map集合的特点以及使用(特点,常见方法,Map集合的遍历) 4.能够掌 ...
- JUC系列回顾之-CountDownLatch底层原理和示例
CountDownLatch 是一个同步工具类,允许一个线程或者多个线程等待其他线程完成操作,再执行. CountDownLatch(int count) 构造一个用给定计数初始化的 CountDow ...
- CountDownLatch 和 CyclicBarrier 的运用及实现原理
I.CountDownLatch 和 CyclicBarrier 的运用 CountDownlatch: 定义: 其是一个线程同步的辅助工具,通过它可以做到使一条线程一直阻塞等待,直到其他线程完成其所 ...
- async/Await使用和原理
await/async是.NetFramework4.5出现的,是语法糖,由编译器提供的功能! await/async 是C#保留关键字,通常是成对出现,一般的建议是:要么不用,要么用到底 async ...
- JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能
摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...
- 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理
[微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...
- Java并发包5--同步工具CountDownLatch、CyclicBarrier、Semaphore的实现原理解析
前言: JUC中提供了很多同步工具类,比如CountDownLatch.CyclicBarrier.Semaphore等,都可以作用同步手段来实现多线程之间的同步效果 一.CountDownLatch ...
随机推荐
- C 国家名字按字母顺序排序
问题 输入五个国家的名字,并按字母的顺序排列输出 分析 知识点 strcpy(1,2):将字符串2复制到字符数组1中 strcmp(1,2):比较字符串大小 二维数组 代码 #include & ...
- 【译】融入人工智能的 eShop – 全面的智能应用示例
原文 | Jeremy Likness 翻译 | 郑子铭 人工智能 (AI) 是一种强大的工具,它可以增强您的应用程序,提供更好的个性化定制体验,满足客户的独特需求,同时提高内部运营的质量和效率.虽然 ...
- linux mint安装Scala
Scala由java编写,需要前期安装jdk 面向函数式编程 1.下载 Scala 二进制包2.11.8 http://www.scala-lang.org/downloads 解压到/usr/loc ...
- Codeforces 232 B Table 题解 [ 蓝 ] [ 分组背包 ] [ 组合数学 ] [ 循环节 ]
Codeforces 232B Table. 蒟蒻模拟赛上场切的一道蓝,非常难以置信我竟然能做蓝题. 这题的数据范围初看还是比较坑的,\(10^{18}\) 的值域很容易让人往矩阵加速那方面想.实际上 ...
- 【忍者算法】从十字路口相遇到链表交点:探索相交链表问题|LeetCode第160题 相交链表
从十字路口相遇到链表交点:探索相交链表问题 生活中的相遇问题 想象两个人从不同的地方出发,最后在一个十字路口相遇.他们可能走过不同长度的路程,但最终会在同一个点汇合.这就很像我们今天要讨论的相交链表问 ...
- 刚刚!百度搜索“换脑”引爆AI圈,正式接入DeepSeek R1满血版
一.今天发现百度搜索出现已接入DeepSeek的提示,再也不用担心使用DeepSeek时出现"服务器繁忙,请稍后再试."的问题了. 在百度搜索首页出现[即刻体验AI搜索Deep ...
- sql server 新建用户数据库授权
必须对数据库进行 db_owner 授权.
- NolanPro 详细部署教程
自己想办法去弄授权,只提供部署教程 服务器搭建教程 1 诺兰群里找 @NolanNarkbot 点击start 2 群里发送 /check@NolanNarkbot 再找 @NolanNarkbot ...
- 普通文本(.txt)篇章排版样式参考 [文档说明][日志]
把普通文本的篇章排版样式归总一下,供自己参考,当然如果读者能以此借鉴并学习到一些东西,是笔者最大的鼓励. 日志类 [1] 头标 [时间日期][备注][属性]内容 [2] [文件信息][符号][文件信息 ...
- 传统Item-Based协同过滤推荐算法改进
前言 今天要读的论文为一篇于2009年10月15日发表在<计算机研究与发展>的一篇会议论文,论文针对只根据相似性无法找到准确可靠的最近邻这个问题,提出了结合项目近部等级与相似性求取最近邻的 ...