详细介绍Java中的CyclicBarrier


Posted in Java/Android onApril 13, 2022

CyclicBarrier简介

对于CountDownLatch,其他线程为游戏玩家,比如英雄联盟,主线程为控制游戏开始的线程。在所有的玩家都准备好之前,主线程是处于等待状态的,也就是游戏不能开始。当所有的玩家准备好之后,下一步的动作实施者为主线程,即开始游戏。

对于CyclicBarrier,假设有一家公司要全体员工进行团建活动,活动内容为翻越三个障碍物,每一个人翻越障碍物所用的时间是不一样的。但是公司要求所有人在翻越当前障碍物之后再开始翻越下一个障碍物,也就是所有人翻越第一个障碍物之后,才开始翻越第二个,以此类推。类比地,每一个员工都是一个“其他线程”。当所有人都翻越的所有的障碍物之后,程序才结束。而主线程可能早就结束了,这里我们不用管主线程。

CyclicBarrier源码分析

类的继承关系

CyclicBarrier没有显示继承哪个父类或者实现哪个父接口, 所有AQS和重入锁不是通过继承实现的,而是通过组合实现的。

public class CyclicBarrier {}
```  

### 类的内部类

CyclicBarrier类存在一个内部类Generation,每一次使用的CycBarrier可以当成Generation的实例,其源代码如下

```java
private static class Generation {
boolean broken = false;
}

说明: Generation类有一个属性broken,用来表示当前屏障是否被损坏。

​类的属性

public class CyclicBarrier {

/** The lock for guarding barrier entry */
// 可重入锁
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
// 条件队列
private final Condition trip = lock.newCondition();
/** The number of parties */
// 参与的线程数量
private final int parties;
/* The command to run when tripped */
// 由最后一个进入 barrier 的线程执行的操作
private final Runnable barrierCommand;
/** The current generation */
// 当前代
private Generation generation = new Generation();
// 正在等待进入屏障的线程数量
private int count;
}

说明: 该属性有一个为ReentrantLock对象,有一个为Condition对象,而Condition对象又是基于AQS的,所以,归根到底,底层还是由AQS提供支持。

类的构造函数

CyclicBarrier(int, Runnable)型构造函数

public CyclicBarrier(int parties, Runnable barrierAction) {
// 参与的线程数量小于等于0,抛出异常
if (parties <= 0) throw new IllegalArgumentException();
// 设置parties
this.parties = parties;
// 设置count
this.count = parties;
// 设置barrierCommand
this.barrierCommand = barrierAction;
}

说明: 该构造函数可以指定关联该CyclicBarrier的线程数量,并且可以指定在所有线程都进入屏障后的执行动作,该执行动作由最后一个进行屏障的线程执行。

CyclicBarrier(int)型构造函数

public CyclicBarrier(int parties) {
// 调用含有两个参数的构造函数
this(parties, null);
}

说明: 该构造函数仅仅执行了关联该CyclicBarrier的线程数量,没有设置执行动作。

核心函数 - dowait函数

此函数为CyclicBarrier类的核心函数,CyclicBarrier类对外提供的await函数在底层都是调用该了doawait函数,

其源代码如下:

private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
// 保存当前锁
final ReentrantLock lock = this.lock;
// 锁定
lock.lock();
try {
// 保存当前代
final Generation g = generation;

if (g.broken) // 屏障被破坏,抛出异常
throw new BrokenBarrierException();

if (Thread.interrupted()) { // 线程被中断
// 损坏当前屏障,并且唤醒所有的线程,只有拥有锁的时候才会调用
breakBarrier();
// 抛出异常
throw new InterruptedException();
}

// 减少正在等待进入屏障的线程数量
int index = --count;
if (index == 0) { // 正在等待进入屏障的线程数量为0,所有线程都已经进入
// 运行的动作标识
boolean ranAction = false;
try {
// 保存运行动作
final Runnable command = barrierCommand;
if (command != null) // 动作不为空
// 运行
command.run();
// 设置ranAction状态
ranAction = true;
// 进入下一代
nextGeneration();
return 0;
} finally {
if (!ranAction) // 没有运行的动作
// 损坏当前屏障
breakBarrier();
}
}

// loop until tripped, broken, interrupted, or timed out
// 无限循环
for (;;) {
try {
if (!timed) // 没有设置等待时间
// 等待
trip.await();
else if (nanos > 0L) // 设置了等待时间,并且等待时间大于0
// 等待指定时长
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) { // 设置了等待时间,并且等待时间小于0
// 损坏屏障
breakBarrier();
// 抛出异常
throw new TimeoutException();
}
}
} finally {
// 释放锁
lock.unlock();
}
}

核心函数 - nextGeneration函数

此函数在所有线程进入屏障后会被调用,即生成下一个版本,所有线程又可以重新进入到屏障中,

其源代码如下:

private void nextGeneration() {
// signal completion of last generation
// 唤醒所有线程
trip.signalAll();
// set up next generation
// 恢复正在等待进入屏障的线程数量
count = parties;
// 新生一代
generation = new Generation();
}

在此函数中会调用AQS的signalAll方法,即唤醒所有等待线程。如果所有的线程都在等待此条件,则唤醒所有线程。

其源代码如:

public final void signalAll() {
if (!isHeldExclusively()) // 不被当前线程独占,抛出异常
throw new IllegalMonitorStateException();
// 保存condition队列头节点
Node first = firstWaiter;
if (first != null) // 头节点不为空
// 唤醒所有等待线程
doSignalAll(first);
}

到此这篇关于Java中的 CyclicBarrier详解的文章就介绍到这了!

Java/Android 相关文章推荐
springboot中一些比较常用的注解总结
Jun 11 Java/Android
Java Shutdown Hook场景使用及源码分析
Jun 15 Java/Android
新手入门Jvm-- JVM对象创建与内存分配机制
Jun 18 Java/Android
详解Java实践之适配器模式
Jun 18 Java/Android
详解java如何集成swagger组件
Jun 21 Java/Android
SpringBoot实现异步事件驱动的方法
Jun 28 Java/Android
死磕 java同步系列之synchronized解析
Jun 28 Java/Android
正则表达式拆分url实例代码
Feb 24 Java/Android
Spring Boot 使用 Spring-Retry 进行重试框架
Apr 24 Java/Android
Mybatis-plus配置分页插件返回统一结果集
Jun 21 Java/Android
Java 多线程并发FutureTask
Jun 28 Java/Android
Java实现贪吃蛇游戏的示例代码
Sep 23 Java/Android
Java8 Stream API 提供了一种高效且易于使用的处理数据的方式
Apr 13 #Java/Android
Java的Object类的九种方法
Apr 13 #Java/Android
Java 使用类型为Object的变量指向任意类型的对象
Apr 13 #Java/Android
java中为什么说子类的构造方法默认访问的是父类的无参构造方法
Apr 13 #Java/Android
Spring Cloud Netflix 套件中的负载均衡组件 Ribbon
Apr 13 #Java/Android
Android开发之WECHAT微信小程序路由跳转的两种形式
Apr 12 #Java/Android
JavaWeb Servlet开发注册页面实例
You might like
PHP中文处理 中文字符串截取(mb_substr)和获取中文字符串字数
2011/11/10 PHP
PHP中strtr字符串替换用法详解
2014/11/26 PHP
Zend Framework教程之配置文件application.ini解析
2016/03/10 PHP
PHP按符号截取字符串的指定部分的实现方法
2018/09/10 PHP
可缩放Reloaded-一个针对可缩放元素的复用组件
2007/03/10 Javascript
MooTools 1.2中的Drag.Move来实现拖放
2009/09/15 Javascript
js控制div及网页相关属性的代码
2009/12/19 Javascript
jquery选择器之内容过滤选择器详解
2014/01/27 Javascript
js 操作符汇总
2014/11/08 Javascript
moment.js轻松实现获取当前日期是当年的第几周
2015/02/05 Javascript
jQuery入门之层次选择器实例简析
2015/12/11 Javascript
多个js毫秒倒计时同时进行效果
2016/01/05 Javascript
深入理解js数组的sort排序
2016/05/28 Javascript
简单理解vue中Props属性
2016/10/27 Javascript
JS实现禁止用户使用Ctrl+鼠标滚轮缩放网页的方法
2017/04/28 Javascript
客户端(vue框架)与服务器(koa框架)通信及服务器跨域配置详解
2017/08/26 Javascript
vue下跨域设置的相关介绍
2017/08/26 Javascript
cocos creator Touch事件应用(触控选择多个子节点的实例)
2017/09/10 Javascript
Vue+webpack项目基础配置教程
2018/02/12 Javascript
js中对象和面向对象与Json介绍
2019/01/21 Javascript
[05:17]DOTA2睡衣妹卖萌求签名 CJ第二天全明星影像
2013/07/28 DOTA
[02:29]完美世界高校联赛上海赛区回顾
2015/12/15 DOTA
[12:21]VICI vs TNC (BO3)
2018/06/07 DOTA
分享Python开发中要注意的十个小贴士
2016/08/30 Python
python snownlp情感分析简易demo(分享)
2017/06/04 Python
python微信跳一跳系列之自动计算跳一跳距离
2018/02/26 Python
Python实现图片转字符画的代码实例
2019/02/22 Python
使用HTML5的链接预取功能(link prefetching)给网站提速
2012/12/13 HTML / CSS
美国排名第一的泳池用品直接来源:In The Swim
2019/09/23 全球购物
中学生学习生活的自我评价
2013/10/26 职场文书
信用社竞聘演讲稿
2014/05/16 职场文书
运动会广播稿200字
2014/10/18 职场文书
青岛海底世界导游词
2015/02/11 职场文书
隐形的翅膀观后感
2015/06/10 职场文书
sql server 累计求和实现代码
2022/02/28 SQL Server
mysql使用FIND_IN_SET和group_concat两个方法查询上下级机构
2022/04/20 MySQL