CyclicBarrier是一个用于线程同步的辅助类,它允许一组线程等待彼此,直到所有线程都到达集合点,然后执行某个设定的任务。

举个例子:几个人约定了某个地方集中,然后一起出发去旅行。每个参与的人就是一个线程,CyclicBarrier就是那个集合点,所有人到了之后,就一起出发。

CyclicBarrier的构造函数有两个:

 // parties是参与等待的线程的数量,barrierAction是所有线程达到集合点之后要做的动作
public CyclicBarrier(int parties, Runnable barrierAction); // 达到集合点之后不执行操作的构造函数
public CyclicBarrier(int parties)

CyclicBarrier只是记录线程的数目,CyclicBarrier是不创建任何线程的。线程是通过调用CyclicBarrier的await方法来等待其他线程,如果调用await方法的线程数目达到了预设值,也就是上面构造方法中的parties,CyclicBarrier就会开始执行barrierAction。

因此我们来看CyclicBarrier的核心方法dowait,也就是await方法调用的私有方法:

 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();
}
// count就是预设的parties,count减1的值表示还剩余几个
// 线程没有达到该集合点
int index = --count;
// index为0表示所有的线程都已经达到集合点,这时
// 占用最后一个线程,执行运行设定的任务
if (index == 0) {
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
// 唤醒其他等待的线程,
// 更新generation以便下一次运行
nextGeneration();
return 0;
} finally {
// 如果运行任务时发生异常,设置状态为broken
// 并且唤醒其他等待的线程
if (!ranAction)
breakBarrier();
}
} // 还有线程没有调用await,进入循环等待直到其他线程
// 达到集合点或者等待超时
for (;;) {
try {
// 如果没有设置超时,进行无超时的等待
if (!timed)
trip.await();
// 有超时设置,进行有超时的等待
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
// generation如果没有被更新表示还是当前的运行
// (generation被更新表示集合完毕并且任务成功),
// 在状态没有被设置为broken状态的情况下,遇到线程
// 中断异常表示当前线程等待失败,需要设置为broken
// 状态,并且抛出中断异常
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// else对应的条件为:g != generation || g.broken
// 表示要么generation已经被更新意味着所有线程已经到达
// 集合点并且任务执行成功,要么就是是broken状态意味着
// 任务执行失败,无论哪种情况所有线程已经达到集合点,当
// 前线程要结束等待了,发生了中断异常,需要中断当前线程
// 表示遇到了中断异常。
Thread.currentThread().interrupt();
}
} // 如果发现当前状态为broken,抛出异常
if (g.broken)
throw new BrokenBarrierException();
// generation被更新表示所有线程都已经达到集合点
// 并且预设任务已经完成,返回该线程进入等待顺序号
if (g != generation)
return index;
// 等待超时,设置为broken状态并且抛出超时异常
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}

1. 任何一个线程等待时发生异常,CyclicBarrier都将被设置为broken状态,运行都会失败

2. 每次运行成功之后CyclicBarrier都会清理运行状态,这样CyclicBarrier可以重新使用

3. 对于设置了超时的等待,在发生超时的时候会引起CyclicBarrier的broken

源码阅读 - java.util.concurrent (四)CyclicBarrier的更多相关文章

  1. 源码阅读 - java.util.concurrent (一)

    java.util.concurrent这个包大致可以分为五个部分: Aomic数据类型 这部分都被放在java.util.concurrent.atomic这个包里面,实现了原子化操作的数据类型,包 ...

  2. 源码阅读 - java.util.concurrent (三)ConcurrentHashMap

    在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:ConcurrentMap.本篇文章主要关注ConcurrentMap接口以及它的Hash版本的实现Concu ...

  3. 源码阅读 - java.util.concurrent (二)CAS

    背景 在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题. ...

  4. Java源码之 java.util.concurrent 学习笔记01

    准备花点时间看看 java.util.concurrent这个包的源代码,来提高自己对Java的认识,努力~~~ 参阅了@梧留柒的博客!边看源码,边通过前辈的博客学习! 包下的代码结构分类: 1.ja ...

  5. 源码(09) -- java.util.Arrays

    java.util.Arrays 源码分析 ------------------------------------------------------------------------------ ...

  6. 如何阅读Java源码 阅读java的真实体会

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心.   说到技术基础,我打个比 ...

  7. 源码(03) -- java.util.Collection<E>

     java.util.Collection<E> 源码分析(JDK1.7) -------------------------------------------------------- ...

  8. JDK1.8源码(五)——java.util.Vector类

    JDK1.8源码(五)--java.lang. https://www.cnblogs.com/IT-CPC/p/10897559.html

  9. JDK1.8源码(六)——java.util.LinkedList 类

    上一篇博客我们介绍了List集合的一种典型实现 ArrayList,我们知道 ArrayList 是由数组构成的,本篇博客我们介绍 List 集合的另一种典型实现 LinkedList,这是一个有链表 ...

随机推荐

  1. debian8 root无法远程登录解决办法

    改一下root 密码,应该就能本地登录了. 改/etc/ssh/sshd.conf,然后重启ssh就能远程登录了:PermitRootLogin yesPermitEmptyPasswords no

  2. 用MVVM模式开发中遇到的零散问题总结(4)——自制摄像头拍摄大头贴控件

    原文:用MVVM模式开发中遇到的零散问题总结(4)--自制摄像头拍摄大头贴控件 一直有个疑问,为什么silverlight对摄像头支持这么好,WPF却一个库都没有....于是我各种苦恼啊,各种Code ...

  3. 怎么给开源项目提PR?

    1. fork 你要的项目 2. 下载到本地 相关步骤如下 在你需要的文件夹下面,右键 git bash 命令,打开 git 命令框 执行如下指令可将项目代码下载到当前目录 ~~~ git clone ...

  4. C# Windows服务以指定用户运行

    参考一下 https://bbs.csdn.net/topics/330151879 服务程序以Local System安装运行没问题,但用这个账户运行的服务无法访问局域网共享资源,比较麻烦,所以想指 ...

  5. Win8 Metro(C#)数字图像处理--2.62图像对数增强

    原文:Win8 Metro(C#)数字图像处理--2.62图像对数增强  [函数名称]   对数增强      WriteableBitmap LogenhanceProcess(Writeabl ...

  6. C#破解access数据库密码方法

    原文:C#破解access数据库密码方法 using System; using System.Collections.Generic; using System.IO; using System.L ...

  7. mfc动态显示图片

    参考:https://blog.csdn.net/pudongdong/article/details/69396600 之前写过win32动态显示图片的博客,这次用到了mfc.原理是一样的. OnI ...

  8. 零元学Expression Blend 4 - Chapter 35 讨厌!!我不想一直重复设定!!『Template Binding』使用前後的差异

    原文:零元学Expression Blend 4 - Chapter 35 讨厌!!我不想一直重复设定!!『Template Binding』使用前後的差异 因为先前写到自制Button时需特别注意T ...

  9. Portal for ArcGIS 资源承载数据类型

    在Portal中数据主要分为两大类:Web内容与桌面内容.对于Web内容与桌面内容中的每个项目(item)又被具体分为maps,layers, styles, tools,applications,和 ...

  10. SQL Server Update:使用 TOP 限制更新的数据

    原文 使用 TOP 限制更新的数据 可以使用 TOP 子句来限制 UPDATE 语句中修改的行数.当 TOP (n) 子句与 UPDATE 一起使用时,将针对随机选择的 n 行执行删除操作.例如,假设 ...