CyclicBarrier是通过ReentrantLock(独占锁)和Condition来实现的。下面,我们分析CyclicBarrier中3个核心函数: 构造函数, await()作出分析。


1. 构造函数

CyclicBarrier的构造函数共2个:CyclicBarrier 和 CyclicBarrier(int parties, Runnable barrierAction)。第1个构造函数是调用第2个构造函数来实现的,下面第2个构造函数的源码。

public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
// parties表示“必须同时到达barrier的线程个数”。
this.parties = parties;
// count表示“处在等待状态的线程个数”。
this.count = parties;
// barrierCommand表示“parties个线程到达barrier时,会执行的动作”。
this.barrierCommand = barrierAction;
}

2. 等待函数

CyclicBarrier.java中await()方法如下:

public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen;
}
}

说明 :await()是通过dowait()实现的。

private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
// 获取“独占锁(lock)”
lock.lock();
try {
// 保存“当前的generation”
final Generation g = generation; // 若“当前generation已损坏”,则抛出异常。
if (g.broken)
throw new BrokenBarrierException(); // 如果当前线程被中断,则通过breakBarrier()终止CyclicBarrier,唤醒CyclicBarrier中所有等待线程。
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
} // 将“count计数器”-1
int index = --count;
// 如果index=0,则意味着“有parties个线程到达barrier”。
if (index == 0) { // tripped
boolean ranAction = false;
try {
// 如果barrierCommand不为null,则执行该动作。
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
// 唤醒所有等待线程,并更新generation。
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
} // 当前线程一直阻塞,直到“有parties个线程到达barrier” 或 “当前线程被中断” 或 “超时”这3者之一发生,
// 当前线程才继续执行。
for (;;) {
try {
// 如果不是“超时等待”,则调用awati()进行等待;否则,调用awaitNanos()进行等待。
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
// 如果等待过程中,线程被中断,则执行下面的函数。
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
Thread.currentThread().interrupt();
}
} // 如果“当前generation已经损坏”,则抛出异常。
if (g.broken)
throw new BrokenBarrierException(); // 如果“generation已经换代”,则返回index。
if (g != generation)
return index; // 如果是“超时等待”,并且时间已到,则通过breakBarrier()终止CyclicBarrier,唤醒CyclicBarrier中所有等待线程。
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
// 释放“独占锁(lock)”
lock.unlock();
}
}

说明 :dowait()的作用就是让当前线程阻塞,直到“有parties个线程到达barrier” 或 “当前线程被中断” 或 “超时”这3者之一发生,当前线程才继续执行。
(01) generation是CyclicBarrier的一个成员遍历,它的定义如下:

private Generation generation = new Generation();

private static class Generation {
boolean broken = false;
}

在CyclicBarrier中,同一批的线程属于同一代,即同一个Generation;CyclicBarrier中通过generation对象,记录属于哪一代。
当有parties个线程到达barrier,generation就会被更新换代。

(02) 如果当前线程被中断,即Thread.interrupted()为true;则通过breakBarrier()终止CyclicBarrier。breakBarrier()的源码如下:

private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}

breakBarrier()会设置当前中断标记broken为true,意味着“将该Generation中断”;同时,设置count=parties,即重新初始化count;最后,通过signalAll()唤醒CyclicBarrier上所有的等待线程。

(03) 将“count计数器”-1,即--count;然后判断是不是“有parties个线程到达barrier”,即index是不是为0。
当index=0时,如果barrierCommand不为null,则执行该barrierCommand,barrierCommand就是我们创建CyclicBarrier时,传入的Runnable对象。然后,调用nextGeneration()进行换代工作,nextGeneration()的源码如下:

private void nextGeneration() {
trip.signalAll();
count = parties;
generation = new Generation();
}

首先,它会调用signalAll()唤醒CyclicBarrier上所有的等待线程;接着,重新初始化count;最后,更新generation的值。

(04) 在for(;;)循环中。timed是用来表示当前是不是“超时等待”线程。如果不是,则通过trip.await()进行等待;否则,调用awaitNanos()进行超时等待。

原文地址:http://www.tuicool.com/articles/ERbIven

CyclicBarrier源码分析的更多相关文章

  1. Java - "JUC" CyclicBarrier源码分析

    Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例 CyclicBarrier简介 CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 ...

  2. 并发工具CyclicBarrier源码分析及应用

      本文首发于微信公众号[猿灯塔],转载引用请说明出处 今天呢!灯塔君跟大家讲: 并发工具CyclicBarrier源码分析及应用 一.CyclicBarrier简介 1.简介 CyclicBarri ...

  3. 并发编程之 CyclicBarrier 源码分析

    前言 在之前的介绍 CountDownLatch 的文章中,CountDown 可以实现多个线程协调,在所有指定线程完成后,主线程才执行任务. 但是,CountDownLatch 有个缺陷,这点 JD ...

  4. concurrent(六)同步辅助器CyclicBarrier & 源码分析

    参考文档:Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例:https://www.cnblogs.com/skywang12345/p/3533995.html简介Cy ...

  5. Java并发编程笔记之CyclicBarrier源码分析

    JUC 中 回环屏障 CyclicBarrier 的使用与分析,它也可以实现像 CountDownLatch 一样让一组线程全部到达一个状态后再全部同时执行,但是 CyclicBarrier 可以被复 ...

  6. 多线程高并发编程(5) -- CountDownLatch、CyclicBarrier源码分析

    一.CountDownLatch 1.概念 public CountDownLatch(int count) {//初始化 if (count < 0) throw new IllegalArg ...

  7. Java并发系列[8]----CyclicBarrier源码分析

    现实生活中我们经常会遇到这样的情景,在进行某个活动前需要等待人全部都齐了才开始.例如吃饭时要等全家人都上座了才动筷子,旅游时要等全部人都到齐了才出发,比赛时要等运动员都上场后才开始.在JUC包中为我们 ...

  8. CyclicBarrier 源码分析

    CyclicBarrier CyclicBarrier 是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point) 之后同时释放执行.CyclicB ...

  9. 【JUC】JDK1.8源码分析之CyclicBarrier(四)

    一.前言 有了前面分析的基础,现在,接着分析CyclicBarrier源码,CyclicBarrier类在进行多线程编程时使用很多,比如,你希望创建一组任务,它们并行执行工作,然后在进行下一个步骤之前 ...

随机推荐

  1. Oracle同义词。。。

    同义词 --私有同义词--私有同义词权限grant create synonym to scott;--创建私有同义词create synonym dp for scott.dept;--将查询dep ...

  2. Oracle单行函数。。。

    单行函数 --字符函数--1.ASCII 返回与指定的字符对应的十进制数;select ascii('A') A,ascii('a') a,ascii('0') zero,ascii(' ') spa ...

  3. ADO学习笔记之注入漏洞与参数化查询

    ADO学习笔记之注入漏洞与参数化查询 作为新手,在学习ADO程序时,使用 sql 语言查询数据时,很容易写类似如下代码: using (SqlConnection con = new SqlConne ...

  4. js加密,三种编码方式

      ·escape(69个):*/@+-._0-9a-zA-Z     ·encodeURI(82个):!#$&’()*+,/:;=?@-._~0-9a-zA-Z     ·encodeURI ...

  5. python.h没有那个文件或目录解决方法

    我用的是Deepin Linux,这应该是linux平台的问题,别的linux os也是执行安装,命令不同而已,windows和Mac不太清楚. 如果你使用的是python2.x,那么使用下面的语句: ...

  6. ps钢笔工具路径问题

    问题描述:ps钢笔工具画出路径后用文字工具打字 路径出现一个空心圆点字,不能在路径上打字或者无法确认终止的位置. 解决:1.如果要在路径上全都打满字,要将文字对齐改为左对齐,2.如果要实现自定义结束位 ...

  7. Remote System Explorer Operation在eclipse后台一直跑 解决办法

    在用eclipse开发时,经常遇到卡死的情况,其中一种就是右下角出现:“Remote System Explorer Operation”,解决方案如下: 第一步:Eclipse -> Pref ...

  8. 初学者:Git常用命令总结

    git init      在本地新建一个repo,进入一个项目目录,执行git init,会初始化一个repo,并在当前文件夹下创建一个.git文件夹.   git clone      获取一个u ...

  9. javascript面向对象继承和原型

    一.理解什么是对象:任何东西都可以是对象,对象就是一组无序属性的集合 对象具有属性和方法1.1 属性的类型属性内部又定义了两种属性:数据属性和访问器属性 (1)数据属性:有4个描述的行为 Config ...

  10. <已解决>使用selector设置Button按下松开的样式以及 <item> tag requires a 'drawable' attribute or child tag defining a drawable 报错

    <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="ht ...