CyclicBarrier原理
转载:http://www.cnblogs.com/skywang12345/p/3533995.html
CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
注意比较CountDownLatch和CyclicBarrier:
(01) CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。
(02) CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。
CyclicBarrier函数列表

- CyclicBarrier(int parties)
- 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。
- CyclicBarrier(int parties, Runnable barrierAction)
- 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。
- int await()
- 在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
- int await(long timeout, TimeUnit unit)
- 在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。
- int getNumberWaiting()
- 返回当前在屏障处等待的参与者数目。
- int getParties()
- 返回要求启动此 barrier 的参与者数目。
- boolean isBroken()
- 查询此屏障是否处于损坏状态。
- void reset()
- 将屏障重置为其初始状态。

CyclicBarrier数据结构
CyclicBarrier的UML类图如下:
CyclicBarrier是包含了"ReentrantLock对象lock"和"Condition对象trip",它是通过独占锁实现的。下面通过源码去分析到底是如何实现的。
CyclicBarrier源码分析(基于JDK1.7.0_40)
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()进行超时等待。
CyclicBarrier的使用示例
示例1
新建5个线程,这5个线程达到一定的条件时,它们才继续往后运行。

- 1 import java.util.concurrent.CyclicBarrier;
- 2 import java.util.concurrent.BrokenBarrierException;
- 3
- 4 public class CyclicBarrierTest1 {
- 5
- 6 private static int SIZE = 5;
- 7 private static CyclicBarrier cb;
- 8 public static void main(String[] args) {
- 9
- 10 cb = new CyclicBarrier(SIZE);
- 11
- 12 // 新建5个任务
- 13 for(int i=0; i<SIZE; i++)
- 14 new InnerThread().start();
- 15 }
- 16
- 17 static class InnerThread extends Thread{
- 18 public void run() {
- 19 try {
- 20 System.out.println(Thread.currentThread().getName() + " wait for CyclicBarrier.");
- 21
- 22 // 将cb的参与者数量加1
- 23 cb.await();
- 24
- 25 // cb的参与者数量等于5时,才继续往后执行
- 26 System.out.println(Thread.currentThread().getName() + " continued.");
- 27 } catch (BrokenBarrierException e) {
- 28 e.printStackTrace();
- 29 } catch (InterruptedException e) {
- 30 e.printStackTrace();
- 31 }
- 32 }
- 33 }
- 34 }

运行结果:

- Thread-1 wait for CyclicBarrier.
- Thread-2 wait for CyclicBarrier.
- Thread-3 wait for CyclicBarrier.
- Thread-4 wait for CyclicBarrier.
- Thread-0 wait for CyclicBarrier.
- Thread-0 continued.
- Thread-4 continued.
- Thread-2 continued.
- Thread-3 continued.
- Thread-1 continued.

结果说明:主线程中新建了5个线程,所有的这些线程都调用cb.await()等待。所有这些线程一直等待,直到cb中所有线程都达到barrier时,这些线程才继续运行!
示例2
新建5个线程,当这5个线程达到一定的条件时,执行某项任务。

- 1 import java.util.concurrent.CyclicBarrier;
- 2 import java.util.concurrent.BrokenBarrierException;
- 3
- 4 public class CyclicBarrierTest2 {
- 5
- 6 private static int SIZE = 5;
- 7 private static CyclicBarrier cb;
- 8 public static void main(String[] args) {
- 9
- 10 cb = new CyclicBarrier(SIZE, new Runnable () {
- 11 public void run() {
- 12 System.out.println("CyclicBarrier's parties is: "+ cb.getParties());
- 13 }
- 14 });
- 15
- 16 // 新建5个任务
- 17 for(int i=0; i<SIZE; i++)
- 18 new InnerThread().start();
- 19 }
- 20
- 21 static class InnerThread extends Thread{
- 22 public void run() {
- 23 try {
- 24 System.out.println(Thread.currentThread().getName() + " wait for CyclicBarrier.");
- 25
- 26 // 将cb的参与者数量加1
- 27 cb.await();
- 28
- 29 // cb的参与者数量等于5时,才继续往后执行
- 30 System.out.println(Thread.currentThread().getName() + " continued.");
- 31 } catch (BrokenBarrierException e) {
- 32 e.printStackTrace();
- 33 } catch (InterruptedException e) {
- 34 e.printStackTrace();
- 35 }
- 36 }
- 37 }
- 38 }

运行结果:

- Thread-1 wait for CyclicBarrier.
- Thread-2 wait for CyclicBarrier.
- Thread-3 wait for CyclicBarrier.
- Thread-4 wait for CyclicBarrier.
- Thread-0 wait for CyclicBarrier.
- CyclicBarrier's parties is: 5
- Thread-0 continued.
- Thread-4 continued.
- Thread-2 continued.
- Thread-3 continued.
- Thread-1 continued.

结果说明:主线程中新建了5个线程,所有的这些线程都调用cb.await()等待。所有这些线程一直等待,直到cb中所有线程都达到barrier时,执行新建cb时注册的Runnable任务。
CyclicBarrier原理的更多相关文章
- CyclicBarrier 原理(秒懂)
疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 面试必备 + 面试必备 [博客园总入口 ] 疯狂创客圈 经典图书 : <Sprin ...
- Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例
概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...
- Java 线程同步组件 CountDownLatch 与 CyclicBarrier 原理分析
1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个线程同步 ...
- ☕【Java深层系列】「并发编程系列」让我们一起探索一下CyclicBarrier的技术原理和源码分析
CyclicBarrier和CountDownLatch CyclicBarrier和CountDownLatch 都位于java.util.concurrent这个包下,其工作原理的核心要点: Cy ...
- 【Java并发编程实战】-----“J.U.C”:CyclicBarrier
在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...
- Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例
概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 ...
- CountDownLatch,CyclicBarrier,Semaphore
CountDownLatch是倒数,doneSignal = new CountDownLatch(LATCH_SIZE);赋初值后,在主线程中等待doneSignal.await();其它线程中,每 ...
- Java - "JUC" CyclicBarrier源码分析
Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例 CyclicBarrier简介 CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 ...
- 并发包下常见的同步工具类详解(CountDownLatch,CyclicBarrier,Semaphore)
目录 1. 前言 2. 闭锁CountDownLatch 2.1 CountDownLatch功能简介 2.2 使用CountDownLatch 2.3 CountDownLatch原理浅析 3.循环 ...
随机推荐
- TTabControl、TMemo组件(制作一个简单的多文本编辑框)
TTabControl包含一列字符串标签的tabs 每个标签控制一个对象 首先创建一个TForm;接下来添加TTabControl组件和一个文件对话框TOpenDialog(用于添加文件),然后在TT ...
- bzoj1834 [ZJOI2010]network 网络扩容
第一问跑最大流,第二问新建一条边连接0和1,流量为上第一问的答案+k,费用为0,接下来图中每条边拆成两条边,第一条容量为C费用为0,第二条容量无穷费用为W,再跑一遍费用流即可. 代码 #include ...
- Codeforces Beta Round #93 (Div. 1 Only) D. Fibonacci Sums
先考虑一个斐波那契数能分成其他斐波那契数的方案,假如f[i]表示第i个斐波那契数,那么只要对他进行拆分,f[i-1]这个数字必定会存在.知道这一点就可以进行递推了.先将数字分成最少项的斐波那契数之和, ...
- fackbook的Fresco (FaceBook推出的Android图片加载库-Fresco)
[Android开发经验]FaceBook推出的Android图片加载库-Fresco 欢迎关注ndroid-tech-frontier开源项目,定期翻译国外Android优质的技术.开源库.软件 ...
- LIKE 某个变量
declare i ); n number; begin i:='%D0FC02EAR11005%'; select po_header_id into n from po_headers_all w ...
- springmvcの神总结のreadme
********李守宏springmvc******** 3.== --\springmvc一个controller实现多个方法 ----\继承MultiActionController ----\配 ...
- Deep Learning 深度学习 学习教程网站集锦(转)
http://blog.sciencenet.cn/blog-517721-852551.html 学习笔记:深度学习是机器学习的突破 2006-2007年,加拿大多伦多大学教授.机器学习领域的泰斗G ...
- 二项分布 多项分布 伽马函数 Beta分布
http://blog.csdn.net/shuimu12345678/article/details/30773929 0-1分布: 在一次试验中,要么为0要么为1的分布,叫0-1分布. 二项分布: ...
- 开启xp_cmdshell
--打开xp_cmdshell EXEC sp_configure 'show advanced options', 1GORECONFIGUREGOEXEC sp_configure 'xp_cmd ...
- ASP.NET MVC5 新特性:Attribute路由使用详解 (转载)
1.什么是Attribute路由?怎么样启用Attribute路由? 微软在 ASP.NET MVC5 中引入了一种新型路由:Attribute路由,顾名思义,Attribute路由是通过Attrib ...