CyclicBarrier回环屏障深度解析
1. 前沿
从上一节的CountDownLatch的学习,我们发现其只能使用一次,当state递减为0后,就没有用了,需要重新新建一个计数器。那么我们有没有可以复用的计数器呢?当然,JUC包给我们提供了CyclicBarrier回环屏障来实现计数器的复用。
2. 概念讲解
何为回环:当所有等待线程执行完成后,重置CyclicBarrier的状态,使得它能被复用。
何为屏障:线程调用await方法后就会被阻塞,这个阻塞点就叫屏障点,等所有线程都调用await方法后,线程们就会突破屏障,继续往下运行。
3. 案例

4. 源码分析
- 构造函数
// 一个入参的构造函数
public CyclicBarrier(int parties) {
// 调用还是两个入参的构造函数
this(parties, null);
} public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
// 将入参计数器值赋给count和线程数parties
this.parties = parties;
this.count = parties;
// 计数器count=0时,执行下面barrierCommand的功能
this.barrierCommand = barrierAction;
}
- await()
public int await() throws InterruptedException, BrokenBarrierException {
try {
// 实际调用的dowait方法
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
// 回环屏障底层是用ReentrantLock独占锁实现,其底层还是基于AQS实现
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
// 如果回环屏障是broken=true状态,抛出异常。因为dowait之前broken一定是false的
if (g.broken)
throw new BrokenBarrierException();
// 如果线程interrupted了,那么打破屏障,代码往下执行
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
// 计数器递减1
int index = --count;
// 当计数器为0时,打破屏障
if (index == 0) { // tripped
boolean ranAction = false;
try {
// 我们代码中调用两个参数的构造函数时,传入的一个任务
final Runnable command = barrierCommand;
// 如果任务不为空,那么在回环屏障打破的时候,执行我们自定义的任务。
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
// 如果try方法出现异常,没有正常将ranAction设置为true,那么finally里强行打破屏障
if (!ranAction)
breakBarrier();
}
}
// 以下是设置了超时时间的dowait方法实现,当等待时间超过了超时时间时,屏障等待也会结束
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
} if (g.broken)
throw new BrokenBarrierException(); if (g != generation)
return index; if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
// 打破屏障的方法
private void breakBarrier() {
// 设置打破状态为true
generation.broken = true;
// 将线程数重新赋给计数器count,这是保证屏障复用的关键。
count = parties;
// 唤醒其他所有因为调用await方法而发生阻塞的线程
trip.signalAll();
}
5. 总结
当我们创建回环屏障对象时,传入的计数器值M,前M-1个线程调用await方法时,获得独占锁,串行话执行dowait方法,都将count递减1,并且将M-1个线程加入到trip的条件队列中去。当最后一个线程执行到await方法时,最终将count置为了0,同时唤醒trip条件队列中所有被阻塞的线程,使得所有的M个线程继续往下执行。
CyclicBarrier回环屏障深度解析的更多相关文章
- 回环屏障CyclicBarrier
上一篇说的CountDownLatch是一个计数器,类似线程的join方法,但是有一个缺陷,就是当计数器的值到达0之后,再调用CountDownLatch的await和countDown方法就会立刻返 ...
- thread_CyclicBarrier回环栅栏
CyclicBarrier回环栅栏,字面意思是可循环使用(Cyclic)的屏障(Barrier).通过它可以实现让一组线程等待至某个状态之后再全部同时执行. 它要做的事情是,让一组线程到达一个屏障(也 ...
- 回环栅栏CyclicBarrier
通过它可以实现让一组线程等待至某个状态之后再全部同时执行.叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用.我们暂且把这个状态就叫做barrier,当调用await()方 ...
- 并发编程-concurrent指南-回环栅栏CyclicBarrier
字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行. java.util.concurrent.CyclicBarrier 类是一种同步机制,它能够对处理一些算法的线程实现同步 ...
- 一个基于深度学习回环检测模块的简单双目 SLAM 系统
转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12634631.html 写在前面 最近在搞本科毕设,关于基于深度学 ...
- ORB-SLAM(六)回环检测
上一篇提到,无论在单目.双目还是RGBD中,追踪得到的位姿都是有误差的.随着路径的不断延伸,前面帧的误差会一直传递到后面去,导致最后一帧的位姿在世界坐标系里的误差有可能非常大.除了利用优化方法在局部和 ...
- Kafka深度解析
本文转发自Jason’s Blog,原文链接 http://www.jasongj.com/2015/01/02/Kafka深度解析 背景介绍 Kafka简介 Kafka是一种分布式的,基于发布/订阅 ...
- mybatis 3.x源码深度解析与最佳实践(最完整原创)
mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...
- Kafka深度解析(如何在producer中指定partition)(转)
原文链接:Kafka深度解析 背景介绍 Kafka简介 Kafka是一种分布式的,基于发布/订阅的消息系统.主要设计目标如下: 以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上数据也能 ...
随机推荐
- mfc c++优化
1.不住求精度时,尽量使用单精度浮点型2.使用32位数据类型3.使用有符号和无符号整型: 前提:无需考虑正负时 double x; int i; x = i; 使用有符号:unsigned int i ...
- Guava中EventBus分析
EventBus 1. 什么是EventBus 总线(Bus)一般指计算机各种功能部件之间传送信息的公共通信干线,而EventBus则是事件源(publisher)向订阅方(subscriber)发送 ...
- Docker 入门介绍
Docker是什么 从发布到现在 docker一直很受关注,在一定程度是改变了软件行业 如果你还不知道 docker 是什么是不是有点out了,接下来我们来介绍docker是什么,解决了什么问题,好处 ...
- Impala 3.3.0 源码编译安装
最新编译Apache-impala 的心酸历程.大概花了10天才整好,极度的崩溃!!!由于国内的上网环境大家都懂的,访问国外的s3.amazonaws.com一些资源库的速度极其感人,尤其 ...
- PyQt(Python+Qt)学习随笔:富文本编辑器QTextEdit功能详解
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.概述 QTextEdit是一个高级的所见即所得的文档查看器和编辑器 ...
- 实验吧 Forms
0x1考察知识 html中value的作用 按钮中用的value 指的是 按钮上要显示的文本 比如'确定,删除 等等字样' 复选框用的value 指的是 这个复选框的值 单选框用的value 和复选框 ...
- python——pandas技巧(处理dataframe每个元素,不用for,而用apply)
用apply处理pandas比用for循环,快了无数倍,测试如下: 我们有一个pandas加载的dataframe如下,features是0和1特征的组合,可惜都是str形式(字符串形式),我们要将其 ...
- jmeter.墨振文档
jmeter 介绍 Apache JMeter是Apache组织开发的基于Java的压力测试工具 (1).它可以用于测试静态和动态资源,例如静态文件.Java 小服务程序.CGI 脚本.Java 对象 ...
- CF1457D XOR-gun
这道题真的把我秀到了,我首先猜了一波结论,打了一个可持久化 \(\text{Trie}\) 加二分的两只 \(\log_2\) 的做法,发现不能 \(PP\) ,然后就一直改到比赛结束还没改过. 然后 ...
- 题解-Enemy is weak
Enemy is weak 求序列 \(a\{n\}\) 中的三元逆序对数量. 数据范围:\(3\le n\le 1e6\). 这题真是一道又好又水的题,可是我看别人的题解做法真是玄学难懂,于是蒟蒻要 ...