Java并发包中CyclicBarrier的工作原理、使用示例
1. CyclicBarrier的介绍与源码分析
CyclicBarrier 的字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。线程进入屏障通过CyclicBarrier的await()方法。
CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
CyclicBarrier还提供一个更高级的构造函数CyclicBarrier(int parties, Runnable barrierAction),用于在线程到达屏障时,优先执行barrierAction这个Runnable对象,方便处理更复杂的业务场景。
构造函数
public CyclicBarrier(int parties) {
this(parties, null);
}
public int getParties() {
return parties;
}
实现原理:在CyclicBarrier的内部定义了一个Lock对象,每当一个线程调用CyclicBarrier的await方法时,将剩余拦截的线程数减1,然后判断剩余拦截数是否为0,如果不是,进入Lock对象的条件队列等待。如果是,执行barrierAction对象的Runnable方法,然后将锁的条件队列中的所有线程放入锁等待队列中,这些线程会依次的获取锁、释放锁,接着先从await方法返回,再从CyclicBarrier的await方法中返回。
await源码
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
dowait源码
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) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
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)
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();
}
}
当最后一个线程到达屏障点,也就是执行dowait方法时,会在return 0 返回之前调用finally块中的breakBarrier方法。
breakBarrier源代码
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
CyclicBarrier主要用于一组线程之间的相互等待,而CountDownLatch一般用于一组线程等待另一组些线程。实际上可以通过CountDownLatch的countDown()和await()来实现CyclicBarrier的功能。即 CountDownLatch中的countDown()+await() = CyclicBarrier中的await()。注意:在一个线程中先调用countDown(),然后调用await()。
其它方法:CycliBarrier对象可以重复使用,重用之前应当调用CyclicBarrier对象的reset方法。
reset源码
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
breakBarrier(); // break the current generation
nextGeneration(); // start a new generation
} finally {
lock.unlock();
}
}
2. 使用示例
package javalearning; import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class CyclicBarrierDemo {
private CyclicBarrier cb = new CyclicBarrier(4);
private Random rnd = new Random(); class TaskDemo implements Runnable{
private String id;
TaskDemo(String id){
this.id = id;
}
@Override
public void run(){
try {
Thread.sleep(rnd.nextInt(1000));
System.out.println("Thread " + id + " will wait");
cb.await();
System.out.println("-------Thread " + id + " is over");
} catch (InterruptedException e) {
} catch (BrokenBarrierException e) {
}
}
} public static void main(String[] args){
CyclicBarrierDemo cbd = new CyclicBarrierDemo();
ExecutorService es = Executors.newCachedThreadPool();
es.submit(cbd.new TaskDemo("a"));
es.submit(cbd.new TaskDemo("b"));
es.submit(cbd.new TaskDemo("c"));
es.submit(cbd.new TaskDemo("d"));
es.shutdown();
}
}
在这个示例中,我们创建了四个线程a、b、c、d,这四个线程提交给了线程池。四个线程不同时间到达cb.await()语句,当四个线程都输出“Thread x will wait”以后才会输出“Thread x is over”。
运行结果
Thread d will wait
Thread a will wait
Thread c will wait
Thread b will wait
-------Thread b is over
-------Thread d is over
-------Thread a is over
-------Thread c is over
3. 参考内容
[1] http://ifeve.com/concurrency-cyclicbarrier/
Java并发包中CyclicBarrier的工作原理、使用示例的更多相关文章
- Java并发包中Semaphore的工作原理、源码分析及使用示例
1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后 ...
- Java并发包中CountDownLatch的工作原理、使用示例
1. CountDownLatch的介绍 CountDownLatch是一个同步工具,它主要用线程执行之间的协作.CountDownLatch 的作用和 Thread.join() 方法类似,让一些线 ...
- Java并发包中Lock的实现原理
1. Lock 的简介及使用 Lock是java 1.5中引入的线程同步工具,它主要用于多线程下共享资源的控制.本质上Lock仅仅是一个接口(位于源码包中的java\util\concurrent\l ...
- Java并发包中CyclicBarrier的源码分析和使用
CyclicBarrier的介绍和源码分析 CyclicBarrier的字母意思是可循环(Cyclic)使用的屏障(Barrier).它要做的事情是,让一组线程到达一个屏障(也可以叫做同步点)时被阻塞 ...
- Java并发包中线程池ThreadPoolExecutor原理探究
一.线程池简介 线程池的使用主要是解决两个问题:①当执行大量异步任务的时候线程池能够提供更好的性能,在不使用线程池时候,每当需要执行异步任务的时候直接new一个线程来运行的话,线程的创建和销毁都是需要 ...
- Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理
Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...
- CyclicBarrier的工作原理及其实例
CyclicBarrier是多线程中一个重要的类,主要用于线程组内部之间的线程的相互等待问题. 1.CyclicBarrier的工作原理 CyclicBarrier大致是可循环利用的屏障,顾名思义,这 ...
- Java 并发包中的读写锁及其实现分析
1. 前言 在Java并发包中常用的锁(如:ReentrantLock),基本上都是排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时 刻可以允许多个读线程访问,但是在写线程访问时,所有 ...
- 转:ListView中getView的工作原理
ListView中getView的工作原理: [1]ListView asks adapter “give me a view” (getView) for each item of the list ...
随机推荐
- Cobbler学习之二--Cobbler的Web管理和维护
Cobbler的Web管理模块和命令行模块是可以分开工作的,没有依赖关系. 1 WebUI的功能 查看所有的对象和配置文件 添加或者删除system,distro, profile 执行“cobble ...
- 「2014-2-23」Note on Preliminary Introduction to Distributed System
今天读了几篇分布式相关的内容,记录一下.非经典论文,非系统化阅读,非严谨思考和总结.主要的着眼点在于分布式存储:好处是,跨越单台物理机器的计算和存储能力的限制,防止单点故障(single point ...
- 手机移动端alert替换方案
//alert ;(function () { var AlertBox = function (options){ this.defaults = { title:"", cal ...
- 关于H5本部缓存localStorage,sessionStorage
HTML5 提供了两种在客户端存储数据的新方法: localStorage - 没有时间限制的数据存储 sessionStorage - 针对一个 session 的数据存储 之前,这些都是由 coo ...
- Microsoft Visual Studio 2010 已安装的模板 没有 “ADO.NET实体数据模型”
2010 sp1才包括entity framework. 装一个补丁即可 地址为:http://www.microsoft.com/zh-CN/download/details.aspx?id=236 ...
- 用Yaml文件进行元素管理【转】
原文:http://www.cnblogs.com/milanmi/p/4636503.html 如界面有一个按钮,id号是test.如果进行对象化的话,就是test.click就可以了.不用每次都要 ...
- requirejs按需加载angularjs文件
之前分享了一篇用ocLazyLoad实现按需加载angular js文件的博客.本来当时想会使用一种方法就行了.可最近刚好有时间,在网上查找了一下requirejs实现angular js文件按需加载 ...
- IO-04. 混合类型数据格式化输入(5)
本题要求编写程序,顺序读入浮点数1.整数.字符.浮点数2,再按照字符.整数.浮点数1.浮点数2的顺序输出. 输入格式: 输入在一行中顺序给出浮点数1.整数.字符.浮点数2,其间以1个空格分隔. 输出格 ...
- C#性能优化之Lazy<T> 实现延迟初始化
在.NET4.0中,可以使用Lazy<T> 来实现对象的延迟初始化,从而优化系统的性能.延迟初始化就是将对象的初始化延迟到第一次使用该对象时.延迟初始化是我们在写程序时经常会遇到的情形,例 ...
- Unity 热更新实例一、C#Light 和UI系统使用实例
接下来我会运用热更新的机制,逐步制作一些例子来阐释脚本系统如何和Unity结合. 脚本不限于使用C#Lite,但是C#Lite会有一些便利之处,请往下看. 结合机制也不限于这一种,但是C#Lite的设 ...