CyclicBarrier是多线程中一个重要的类,主要用于线程组内部之间的线程的相互等待问题。

1.CyclicBarrier的工作原理

CyclicBarrier大致是可循环利用的屏障,顾名思义,这个名字也将这个类的特点给明确地表示出来了。首先,便是可重复利用,说明该类创建的对象可以复用;其次,屏障则体现了该类的原理:每个线程执行时,都会碰到一个屏障,直到所有线程执行结束,然后屏障便会打开,使所有线程继续往下执行。

这里介绍CyclicBarrier的两个构造函数:CyclicBarrier(int parties)和CyclicBarrier(int parties, Runnable barrierAction) :前者只需要声明需要拦截的线程数即可,而后者还需要定义一个等待所有线程到达屏障优先执行的Runnable对象。

实现原理:在CyclicBarrier的内部定义了一个Lock对象,每当一个线程调用await方法时,将拦截的线程数减1,然后判断剩余拦截数是否为初始值parties,如果不是,进入Lock对象的条件队列等待。如果是,执行barrierAction对象的Runnable方法,然后将锁的条件队列中的所有线程放入锁等待队列中,这些线程会依次的获取锁、释放锁。

举例说明:如果一个寝室四个人约好了去球场打球,由于四个人准备工作不同,所以约好在楼下集合,并且四个人集合好之后一起出发去球场。

  1.  
    package concurrent;
  2.  
    import java.util.concurrent.CyclicBarrier;
  3.  
    import java.util.concurrent.*;
  4.  
    import java.util.concurrent.LinkedBlockingQueue;
  5.  
    import java.util.concurrent.ThreadPoolExecutor;
  6.  
    import java.util.concurrent.TimeUnit;
  7.  
    import java.util.*;
  8.  
    public class CyclicBarrierDemo {
  9.  
    private static final ThreadPoolExecutor threadPool=new ThreadPoolExecutor(4,10,60,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
  10.  
    //当拦截线程数达到4时,便优先执行barrierAction,然后再执行被拦截的线程。
  11.  
    private static final CyclicBarrier cb=new CyclicBarrier(4,new Runnable() {
  12.  
    public void run()
  13.  
    {
  14.  
    System.out.println("寝室四兄弟一起出发去球场");
  15.  
    }
  16.  
    });
  17.  
    private static class GoThread extends Thread{
  18.  
    private final String name;
  19.  
    public GoThread(String name)
  20.  
    {
  21.  
    this.name=name;
  22.  
    }
  23.  
    public void run()
  24.  
    {
  25.  
    System.out.println(name+"开始从宿舍出发");
  26.  
    try {
  27.  
    Thread.sleep(1000);
  28.  
    cb.await();//拦截线程
  29.  
    System.out.println(name+"从楼底下出发");
  30.  
    Thread.sleep(1000);
  31.  
    System.out.println(name+"到达操场");
  32.  
     
  33.  
    }
  34.  
    catch(InterruptedException e)
  35.  
    {
  36.  
    e.printStackTrace();
  37.  
    }
  38.  
    catch(BrokenBarrierException e)
  39.  
    {
  40.  
    e.printStackTrace();
  41.  
    }
  42.  
    }
  43.  
    }
  44.  
    public static void main(String[] args) {
  45.  
    // TODO Auto-generated method stub
  46.  
    String[] str= {"李明","王强","刘凯","赵杰"};
  47.  
    for(int i=0;i<4;i++)
  48.  
    {
  49.  
    threadPool.execute(new GoThread(str[i]));
  50.  
    }
  51.  
    try
  52.  
    {
  53.  
    Thread.sleep(4000);
  54.  
    System.out.println("四个人一起到达球场,现在开始打球");
  55.  
    }
  56.  
    catch(InterruptedException e)
  57.  
    {
  58.  
    e.printStackTrace();
  59.  
    }
  60.  
     
  61.  
     
  62.  
    }
  63.  
     
  64.  
    }

运行程序,得到如下结果:

  1.  
    李明开始从宿舍出发
  2.  
    赵杰开始从宿舍出发
  3.  
    王强开始从宿舍出发
  4.  
    刘凯开始从宿舍出发
  5.  
    寝室四兄弟一起出发去球场
  6.  
    赵杰从楼底下出发
  7.  
    李明从楼底下出发
  8.  
    刘凯从楼底下出发
  9.  
    王强从楼底下出发
  10.  
    赵杰到达操场
  11.  
    王强到达操场
  12.  
    李明到达操场
  13.  
    刘凯到达操场
  14.  
    四个人一起到达球场,现在开始打球

以上便是CyclicBarrier使用实例,通过await()方法对线程的拦截,拦截数加1,当拦截数为初始的parties,首先执行了barrierAction,然后对拦截的线程队列依次进行获取锁释放锁。接下来,在这个例子上讲解CyclicBarrier对象的复用特性。

  1.  
    package concurrent;
  2.  
    import java.util.concurrent.CyclicBarrier;
  3.  
    import java.util.concurrent.*;
  4.  
    import java.util.concurrent.LinkedBlockingQueue;
  5.  
    import java.util.concurrent.ThreadPoolExecutor;
  6.  
    import java.util.concurrent.TimeUnit;
  7.  
    import java.util.*;
  8.  
    public class CyclicBarrierDemo {
  9.  
    private static final ThreadPoolExecutor threadPool=new ThreadPoolExecutor(4,10,60,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
  10.  
    //当拦截线程数达到4时,便优先执行barrierAction,然后再执行被拦截的线程。
  11.  
    private static final CyclicBarrier cb=new CyclicBarrier(4,new Runnable() {
  12.  
    public void run()
  13.  
    {
  14.  
    System.out.println("寝室四兄弟一起出发去球场");
  15.  
    }
  16.  
    });
  17.  
    private static class GoThread extends Thread{
  18.  
    private final String name;
  19.  
    public GoThread(String name)
  20.  
    {
  21.  
    this.name=name;
  22.  
    }
  23.  
    public void run()
  24.  
    {
  25.  
    System.out.println(name+"开始从宿舍出发");
  26.  
    try {
  27.  
    Thread.sleep(1000);
  28.  
    cb.await();//拦截线程
  29.  
    System.out.println(name+"从楼底下出发");
  30.  
    Thread.sleep(1000);
  31.  
    System.out.println(name+"到达操场");
  32.  
     
  33.  
    }
  34.  
    catch(InterruptedException e)
  35.  
    {
  36.  
    e.printStackTrace();
  37.  
    }
  38.  
    catch(BrokenBarrierException e)
  39.  
    {
  40.  
    e.printStackTrace();
  41.  
    }
  42.  
    }
  43.  
    }
  44.  
    public static void main(String[] args) {
  45.  
    // TODO Auto-generated method stub
  46.  
    String[] str= {"李明","王强","刘凯","赵杰"};
  47.  
    String[] str1= {"王二","洪光","雷兵","赵三"};
  48.  
    for(int i=0;i<4;i++)
  49.  
    {
  50.  
    threadPool.execute(new GoThread(str[i]));
  51.  
    }
  52.  
    try
  53.  
    {
  54.  
    Thread.sleep(4000);
  55.  
    System.out.println("四个人一起到达球场,现在开始打球");
  56.  
    System.out.println("现在对CyclicBarrier进行复用.....");
  57.  
    System.out.println("又来了一拨人,看看愿不愿意一起打:");
  58.  
    }
  59.  
    catch(InterruptedException e)
  60.  
    {
  61.  
    e.printStackTrace();
  62.  
    }
  63.  
    //进行复用:
  64.  
    for(int i=0;i<4;i++)
  65.  
    {
  66.  
    threadPool.execute(new GoThread(str1[i]));
  67.  
    }
  68.  
    try
  69.  
    {
  70.  
    Thread.sleep(4000);
  71.  
    System.out.println("四个人一起到达球场,表示愿意一起打球,现在八个人开始打球");
  72.  
    //System.out.println("现在对CyclicBarrier进行复用");
  73.  
    }
  74.  
    catch(InterruptedException e)
  75.  
    {
  76.  
    e.printStackTrace();
  77.  
    }
  78.  
     
  79.  
     
  80.  
     
  81.  
    }
  82.  
     
  83.  
    }

运行如下程序,得到:

  1.  
    王强开始从宿舍出发
  2.  
    赵杰开始从宿舍出发
  3.  
    李明开始从宿舍出发
  4.  
    刘凯开始从宿舍出发
  5.  
    寝室四兄弟一起出发去球场
  6.  
    王强从楼底下出发
  7.  
    李明从楼底下出发
  8.  
    刘凯从楼底下出发
  9.  
    赵杰从楼底下出发
  10.  
    王强到达操场
  11.  
    李明到达操场
  12.  
    赵杰到达操场
  13.  
    刘凯到达操场
  14.  
    四个人一起到达球场,现在开始打球
  15.  
    现在对CyclicBarrier进行复用.....
  16.  
    又来了一拨人,看看愿不愿意一起打:
  17.  
    王二开始从宿舍出发
  18.  
    雷兵开始从宿舍出发
  19.  
    洪光开始从宿舍出发
  20.  
    赵三开始从宿舍出发
  21.  
    寝室四兄弟一起出发去球场
  22.  
    洪光从楼底下出发
  23.  
    王二从楼底下出发
  24.  
    雷兵从楼底下出发
  25.  
    赵三从楼底下出发
  26.  
    雷兵到达操场
  27.  
    赵三到达操场
  28.  
    洪光到达操场
  29.  
    王二到达操场
  30.  
    四个人一起到达球场,表示愿意一起打球,现在八个人开始打球

由上面实例可了解CyclicBarrier的工作原理以及复用的特性。

2.通过CountDownLatch实现CyclicBarrier

CountDownLatch通过将await()方法和countDown()方法在不同线程组分别调用,从而实现线程组间的线程等待,即一个线程组等待另一个线程组执行结束再执行。而CyclicBarrier类则是通过调用await()方法实现线程组内的线程等待,即达到需要拦截的线程数,被拦截的线程才会依次获取锁,释放锁。那么将CountDownLatch的用法进行转换,即在同一个线程组内调用await()方法和countDown()方法,则可实现CyclicBarrier类的功能。但是注意的是必须先调用countDown()方法,才能调用await()方法,因为一旦调用await()方法,该线程后面的内容便不再执行,那么count值无法改变。具体代码如下:

  1.  
    package concurrent;
  2.  
     
  3.  
    import java.util.Vector;
  4.  
    import java.util.concurrent.BrokenBarrierException;
  5.  
    import java.util.concurrent.CountDownLatch;
  6.  
    import java.util.concurrent.LinkedBlockingQueue;
  7.  
    import java.util.concurrent.ThreadPoolExecutor;
  8.  
    import java.util.concurrent.TimeUnit;
  9.  
    public class CyclicBarrierWithCount {
  10.  
    private final static CountDownLatch cdl=new CountDownLatch(3);
  11.  
    private final static ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10, 15, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());//使用线程池
  12.  
     
  13.  
    private static class GoThread extends Thread{
  14.  
    private final String name;
  15.  
     
  16.  
    public GoThread(String name)
  17.  
    {
  18.  
    this.name=name;
  19.  
     
  20.  
    }
  21.  
    public void run()
  22.  
    {
  23.  
    System.out.println(name+"开始从宿舍出发");
  24.  
    cdl.countDown();
  25.  
    try
  26.  
    {
  27.  
    Thread.sleep(1000);
  28.  
    cdl.await();//拦截线程
  29.  
    System.out.println(name+"从楼底下出发");
  30.  
    Thread.sleep(1000);
  31.  
    System.out.println(name+"到达操场");
  32.  
    }
  33.  
    catch(InterruptedException e)
  34.  
    {
  35.  
    e.printStackTrace();
  36.  
    }
  37.  
     
  38.  
     
  39.  
     
  40.  
    }
  41.  
    }
  42.  
     
  43.  
     
  44.  
    public static void main(String[] args) {
  45.  
    // TODO Auto-generated method stub
  46.  
     
  47.  
     
  48.  
    String[] str= {"李明","王强","刘凯","赵杰"};
  49.  
    String[] str1= {"王二","洪光","雷兵","赵三"};
  50.  
    for(int i=0;i<4;i++)
  51.  
    {
  52.  
    threadPool.execute(new GoThread(str[i]));
  53.  
    }
  54.  
    try
  55.  
    {
  56.  
    Thread.sleep(4000);
  57.  
    System.out.println("四个人一起到达球场,现在开始打球");
  58.  
    System.out.println("现在对CyclicBarrier进行复用.....");
  59.  
    System.out.println("又来了一拨人,看看愿不愿意一起打:");
  60.  
    }
  61.  
    catch(InterruptedException e)
  62.  
    {
  63.  
    e.printStackTrace();
  64.  
    }
  65.  
    for(int i=0;i<4;i++)
  66.  
    {
  67.  
    threadPool.execute(new GoThread(str1[i]));
  68.  
    }
  69.  
    try
  70.  
    {
  71.  
    Thread.sleep(4000);
  72.  
    System.out.println("四个人一起到达球场,表示愿意一起打球,现在八个人开始打球");
  73.  
    //System.out.println("现在对CyclicBarrier进行复用");
  74.  
    }
  75.  
    catch(InterruptedException e)
  76.  
    {
  77.  
    e.printStackTrace();
  78.  
    }
  79.  
    }
  80.  
     
  81.  
    }

执行上述代码,结果如下:

  1.  
    李明开始从宿舍出发
  2.  
    赵杰开始从宿舍出发
  3.  
    王强开始从宿舍出发
  4.  
    刘凯开始从宿舍出发
  5.  
    王强从楼底下出发
  6.  
    刘凯从楼底下出发
  7.  
    李明从楼底下出发
  8.  
    赵杰从楼底下出发
  9.  
    李明到达操场
  10.  
    赵杰到达操场
  11.  
    王强到达操场
  12.  
    刘凯到达操场
  13.  
    四个人一起到达球场,现在开始打球
  14.  
    现在对CyclicBarrier进行复用.....
  15.  
    又来了一拨人,看看愿不愿意一起打:
  16.  
    王二开始从宿舍出发
  17.  
    洪光开始从宿舍出发
  18.  
    雷兵开始从宿舍出发
  19.  
    赵三开始从宿舍出发
  20.  
    王二从楼底下出发
  21.  
    洪光从楼底下出发
  22.  
    雷兵从楼底下出发
  23.  
    赵三从楼底下出发
  24.  
    洪光到达操场
  25.  
    王二到达操场
  26.  
    雷兵到达操场
  27.  
    赵三到达操场
  28.  
    四个人一起到达球场,表示愿意一起打球,现在八个人开始打球

由上面可知,CountDownLatch一定情况下可以实现CyclicBarrier类的功能。

3.CountDownLatch和CyclicBarrier的比较

1.CountDownLatch是线程组之间的等待,即一个(或多个)线程等待N个线程完成某件事情之后再执行;而CyclicBarrier则是线程组内的等待,即每个线程相互等待,即N个线程都被拦截之后,然后依次执行。

2.CountDownLatch是减计数方式,而CyclicBarrier是加计数方式。

3.CountDownLatch计数为0无法重置,而CyclicBarrier计数达到初始值,则可以重置。

4.CountDownLatch不可以复用,而CyclicBarrier可以复用。

CyclicBarrier的工作原理及其实例的更多相关文章

  1. Webservice工作原理及实例

    Web Service工作原理及实例   一.Web Service基本概念   Web Service也叫XML Web Service WebService是一种可以接收从Internet或者In ...

  2. Ajax工作原理及实例

    1.关于ajax的名字 ajax 的全称是Asynchronous JavaScript and XML,其中,Asynchronous 是异步的意思,它有别于传统web开发中采用的同步的方式. 2. ...

  3. WebService 工作原理及实例教程

    一.WebService到底是什么? 先来看下标准的定义:Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统 ...

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

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

  5. [转载] Web Service工作原理及实例

    一.Web Service基本概念   Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求, ...

  6. 详解AJAX工作原理以及实例讲解(通俗易懂)

    什么是 AJAX ? AJAX = 异步 JavaScript 和 XML. AJAX 是一种用于创建快速动态网页的技术. 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.这意味 ...

  7. tcp/iP协议族——IP工作原理及实例具体解释(下)

     IP协议具体解释 上一篇文章文章主要介绍了IP服务的特点,IPv4头部结构IP分片.并用tcpdump抓取数据包,来观察IP数据报传送过程中IP的格式,以及分片的过程.本文主要介绍IP路由,IP ...

  8. TCP/IP协议族——IP工作原理及实例具体解释(上)

     IP协议具体解释 本文主要介绍了IP服务特点,头部结构,IP分片知识,并用tcpdump抓取数据包.来观察IP数据报传送过程中IP的格式,以及分片的过程. IP头部信息:IP头部信息出如今每一个 ...

  9. ☕【Java深层系列】「并发编程系列」让我们一起探索一下CyclicBarrier的技术原理和源码分析

    CyclicBarrier和CountDownLatch CyclicBarrier和CountDownLatch 都位于java.util.concurrent这个包下,其工作原理的核心要点: Cy ...

随机推荐

  1. 博客 | 基于Travis CI实现Hexo在Github和Coding的同步自动化部署

    文章目录 完成Hexo主题安装和配置 基于Travis CI实现同步部署 参考内容 相关链接 待补充 完成Hexo主题安装和配置 如果您还没有安装Hexo环境,请参考Hexo文档安装,也给出这样两篇博 ...

  2. [BZOJ1194][HNOI2006][强连通分量Tarjan+dfs]潘多拉的盒子

    [BZOJ1194][HNOI2006]潘多拉的盒子 Input 第一行是一个正整数S,表示宝盒上咒语机的个数,(1≤S≤50).文件以下分为S块,每一块描述一个咒语机,按照咒语机0,咒语机1„„咒语 ...

  3. 在java代码中设置margin

    我们平常可以直接在xml里设置margin,如: <ImageView android:layout_margin="5dip" android:src="@dra ...

  4. bin/...的访问被拒绝被拒绝的问题

    复制到bin.... 对路径bin/.... 的访问被拒绝出现这们的问题,把源码管理器中项目的Bin目录删除,重新获取就要以了

  5. UVa 816 (BFS求最短路)

    /*816 - Abbott's Revenge ---代码完全参考刘汝佳算法入门经典 ---strchr() 用来查找某字符在字符串中首次出现的位置,其原型为:char * strchr (cons ...

  6. ol 接入百度地图

    ol5 如何接入百度地图,网上的资料很多,但是大多都有问题,在级别放大时,地图发生扭曲.为此注重研究了下ol5 接入百度地图的方法. 首先明确以下问题: 百度地图的投影是3857. 百度地图的分辨率和 ...

  7. JWT笔记(2)

    上文对JWT模块进行了一个简单的分析.这篇文章稍微做出一些深入的了解. 一,Header篡改攻击 因为JWT的Header是强制有效并且是明文传输(Base64URL编码,几乎等同于明文).那么恶意用 ...

  8. 不厚道一回->Omnifocus 2 for mac license

    rt, 发个Omnifocus 2 for mac license. 其实Omnifocus 2的价格已经还算亲民了..可惜手贱一下子就找到了,所以没买了..不敢独享,所以分享给需要的人..有能力还是 ...

  9. Codeforces #263 div2 解题报告

    比赛链接:http://codeforces.com/contest/462 这次比赛的时候,刚刚注冊的时候非常想好好的做一下,可是网上喝了个小酒之后.也就迷迷糊糊地看了题目,做了几题.一觉醒来发现r ...

  10. bat 处理文件路径 (所在目录,文件名,文件后缀名,完整文件名,无后缀路径)

    echo off setlocal enabledelayedexpansion set "EXCEL_DIR=%cd%\excel" for /R %EXCEL_DIR% %%f ...