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的工作原理、使用示例的更多相关文章

  1. Java并发包中Semaphore的工作原理、源码分析及使用示例

    1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后 ...

  2. Java并发包中CountDownLatch的工作原理、使用示例

    1. CountDownLatch的介绍 CountDownLatch是一个同步工具,它主要用线程执行之间的协作.CountDownLatch 的作用和 Thread.join() 方法类似,让一些线 ...

  3. Java并发包中Lock的实现原理

    1. Lock 的简介及使用 Lock是java 1.5中引入的线程同步工具,它主要用于多线程下共享资源的控制.本质上Lock仅仅是一个接口(位于源码包中的java\util\concurrent\l ...

  4. Java并发包中CyclicBarrier的源码分析和使用

    CyclicBarrier的介绍和源码分析 CyclicBarrier的字母意思是可循环(Cyclic)使用的屏障(Barrier).它要做的事情是,让一组线程到达一个屏障(也可以叫做同步点)时被阻塞 ...

  5. Java并发包中线程池ThreadPoolExecutor原理探究

    一.线程池简介 线程池的使用主要是解决两个问题:①当执行大量异步任务的时候线程池能够提供更好的性能,在不使用线程池时候,每当需要执行异步任务的时候直接new一个线程来运行的话,线程的创建和销毁都是需要 ...

  6. Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理

    Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...

  7. CyclicBarrier的工作原理及其实例

    CyclicBarrier是多线程中一个重要的类,主要用于线程组内部之间的线程的相互等待问题. 1.CyclicBarrier的工作原理 CyclicBarrier大致是可循环利用的屏障,顾名思义,这 ...

  8. Java 并发包中的读写锁及其实现分析

    1. 前言 在Java并发包中常用的锁(如:ReentrantLock),基本上都是排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时 刻可以允许多个读线程访问,但是在写线程访问时,所有 ...

  9. 转:ListView中getView的工作原理

    ListView中getView的工作原理: [1]ListView asks adapter “give me a view” (getView) for each item of the list ...

随机推荐

  1. Object-C中代码如何分离接口和实现

    使用C#习惯了代码的布局为:public (interface,class with static memebers),internal (class with implementation). 比如 ...

  2. 微信小视频复制到手机本地Android APP 分享

    因为需要将拍的宝宝的微信小视频上传到亲宝宝软件,每次去手动找文件比较麻烦,所以做了个微信视频复制到手机本地的APP,做工虽然粗糙,但是绝对实用, 下载地址 http://pan.baidu.com/s ...

  3. Java学习笔记二——标识符和关键字

    标识符 定义 标识符的定义:对各种变量.方法和类等要素命名时使用的字符序列成为标识符. 简单地说,就是凡是自己可以起名字的地方都叫标识符,都要遵守标识符的规则. 命名规则 标识符只能由字母.下划线&q ...

  4. weui 问题

    1.阻止checkbox 被 checked 方法1: $('.weui-check').on('click', function(e){ $(this).attr('disabled', true) ...

  5. LAMP自定义编译安装

    httpd 2.4.4 + mysql-5.5.28 + php-5.4.13编译安装过程: 一.编译安装apache 1.解决依赖关系 httpd-2.4.4需要较新版本的apr和apr-util, ...

  6. Linux下搭建PHP环境

    转载于: http://www.uxtribe.com/php/405.html 该站下有系列PHP文章. 在Linux下搭建PHP环境比Windows下要复杂得多.除了安装Apache,PHP等软件 ...

  7. @MappedSuperclass的用法

    实体类baseEntity.java package com.rock.cft.hibernate; import java.util.Date; import javax.persistence.G ...

  8. A Silverlight Bug ?

    昨日在写Silverlight程序的时候,遇到一个问题,感觉是Silverlight的Bug.使用版本是Silverlight5.异常信息如下: 行: 56错误: Silverlight 应用程序中未 ...

  9. ENode 1.0 - 消息的重试机制的设计思路

    项目开源地址:https://github.com/tangxuehua/enode 上一篇文章,简单介绍了enode框架中消息队列的设计思路,本文介绍一下enode框架中关系消息的重试机制的设计思路 ...

  10. C# WPF 让你的窗口始终钉在桌面上

    IntPtr hWnd = new WindowInteropHelper(Application.Current.MainWindow).Handle; IntPtr hWndProgMan = F ...