本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。

并发编程系列博客传送门

CyclicBarrier简介

CyclicBarrier也是JDK并发包中提供的一个辅助并发工具类。CyclicBarrier的作用是让一组线程互相等待,直到这组线程中所有的线程

都到达同步点(完成某个动作,体现到API上就是调用CyclicBarrier的await方法),这些线程才会继续往下工作。

在相互等待的线程被释放后,CyclicBarrier可以被循环使用。这个从这个类的名字中的Cyclic就可以看出。

CyclicBarrier的构造函数


public CyclicBarrier(int parties) {
this(parties, null);
} public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}

CyclicBarrier提供了两个构造函数。一个构造函数只是指定相互等待的线程个数,另外一个构造函数指定了互相等待的线程个数,还指定了

栅栏打开之后会触发的动作。

CyclicBarrier的典型用法

下面的代码模拟了一个解析Excel的过程:这个Excel有5个sheet,使用5个线程分别去解析这个5个sheet,等5个线程全部解析完成后打印出解析结果。


public class CyclicBarrierTest { public static void main(String[] args) { Map<String, Integer> mockExcelSheet = new HashMap<>();
mockExcelSheet.put("sheet1", 1);
mockExcelSheet.put("sheet2", 2);
mockExcelSheet.put("sheet3", 3);
mockExcelSheet.put("sheet4", 4);
mockExcelSheet.put("sheet5", 5);
AtomicInteger result = new AtomicInteger(0); CyclicBarrier cyclicBarrier = new CyclicBarrier(5,new SummaryClerker(result));
for (int i = 0; i < 5; i++) {
new Thread(new Worker(cyclicBarrier,mockExcelSheet,result,i+1)).start();
}
} private static class Worker implements Runnable { private CyclicBarrier cyclicBarrier;
private Map<String, Integer> mockExcelSheet;
private AtomicInteger result;
private int threadIndex; public Worker(CyclicBarrier cyclicBarrier,
Map<String, Integer> mockExcelSheet,
AtomicInteger result,
int threadIndex) {
this.cyclicBarrier = cyclicBarrier;
this.mockExcelSheet = mockExcelSheet;
this.result = result;
this.threadIndex = threadIndex;
} @Override
public void run() {
String sheetName = "sheet" + threadIndex;
Integer integer = mockExcelSheet.get(sheetName);
int processData = processData(integer);
result.addAndGet(processData);
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} private int processData(int originalData) {
return originalData * 10;
}
} private static class SummaryClerker implements Runnable {
private AtomicInteger result; public SummaryClerker(AtomicInteger result) {
this.result = result;
} @Override
public void run() {
System.out.println("the final result is:" + result.toString());
}
} }

CountDownLatch的区别

CountDownLatchCyclicBarrier功能类似。下面举个列子来说明下这两个类的主要区别。

区别一:强调的重点不一样

CountDownLatch更加强调一组线程等待另外一组线程。还是那之前的场景举例:

小王和他老婆分别请了他们的同事来家里吃晚饭,一共请了6个同事。他们会一直等到6个同时全都到齐了才开始吃晚饭。

这个场景中,小王和他老婆就是线程组A,他们的6个同事就是线程组B,线程组A的线程会一直await,知道线程组B的6个同事全部到达,调用countDown

CyclicBarrier更加强调一组线程之间的互相等待。

小王和公司户外俱乐部的同事相约去爬佘山。他们相约在景区入口处集合,等全部的人都到齐后再一起去爬山。这个景区入口就是一个同步点(栅栏),所有

同事都到齐后这个栅栏会打开。

区别二:可重用性不一样

CountDownLatch计数归零后就不能重复利用了,但是CyclicBarrier可以reset进行重复利用。

简单总结

CyclicBarrier源代码比较简单,这边就不具体分析源代码了。

总的来说,CyclicBarrier的主要功能是一组线程互相等待,线程全部到达同步点后这些线程才继续往下工作。

实现的原理是:先到达的线程调用Condition的await方法,进入waiting状态。最后一个到达的线程会调用signalAll方法唤醒所有线程继续往下工作。

一个小坑

CyclicBarrier的reset方法有一个小坑需要我们注意下。

在调用reset之后,只会重置已经到达屏障的线程(已经调用await的线程)因此会存在一个问题(下面还是以爬山的列子说明这个问题):

两拨人相约去爬山,每波人20个。第一拨人约定上午9点在景区门口集合,第二波人约定10点左右集合。

第一波人中,19个人在9点左右都到达了景区门口了,但是剩下的一个人因为堵车而没来的及赶到。这19个人就在景区门口一直等这个迟到的同事。突然在等的过程中,有个同事身体不舒服,就提议取消这次活动,所以大家都散了。

但是堵车的那个同事还没到,也没人通知他活动取消了。他匆匆忙忙终于还是在9点40左右到达了,但是现在他已经分不清自己是第一波人还是第二波人了,第二波人也不知道这个人其实是属于第一波人的。所以只要第二波人中来了19个人他们就开始去爬山了。

第二波人中最后一个到达的会一直在那等待其他的19个人,但实际上他们已经去爬山了。

其实这种情况可以给线程设置一个超时时间来解决。在这个场景中的体现就是,每个人只等待30分钟,还没到期就打道回府。

并发工具——CyclicBarrier的更多相关文章

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

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

  2. 并发工具CyclicBarrier

    想想一下这样一个场景,有多个人需要过河,河上有一条船,船要等待满10个人才过河,过完河后每个人又各自行动. 这里的人相当于线程,注意这里,每个线程运行到一半的时候,它就要等待一个条件,即船满过河的条件 ...

  3. 并发工具类:CountDownLatch、CyclicBarrier、Semaphore

    在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch.CyclicBarrier.Semaphore. 一.CountDownLatch ...

  4. java 并发工具类CountDownLatch & CyclicBarrier

    一起在java1.5被引入的并发工具类还有CountDownLatch.CyclicBarrier.Semaphore.ConcurrentHashMap和BlockingQueue,它们都存在于ja ...

  5. Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger

    在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...

  6. Java中的并发工具类(CountDownLatch、CyclicBarrier、Semaphore、Exchanger)

    在JDK的并发包里提供了很多有意思的并发工具类.CountDownLatch.CyclicBarrier和Semaphore 工具类提供了一种并发流程控制的手段,Exchanger 工具类则提供了在线 ...

  7. 多线程学习笔记六之并发工具类CountDownLatch和CyclicBarrier

    目录 简介 CountDownLatch 示例 实现分析 CountDownLatch与Thread.join() CyclicBarrier 实现分析 CountDownLatch和CyclicBa ...

  8. 并发工具类(二)同步屏障CyclicBarrier

    前言   JDK中为了处理线程之间的同步问题,除了提供锁机制之外,还提供了几个非常有用的并发工具类:CountDownLatch.CyclicBarrier.Semphore.Exchanger.Ph ...

  9. Java并发(十三):并发工具类——同步屏障CyclicBarrier

    先做总结 1.CyclicBarrier 是什么? CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier).它要做的事情是,让一组线程到达一个屏障(也可以叫同步点) ...

随机推荐

  1. 【总结】办公&编程&学习你可能需要这些小利器!

    偶然想到自己从最开始的编程小白,什么都不懂,看啥啥新鲜的时期,到现在颇有"蓦然回首,那人却在灯火阑珊处"的感觉,遂想整理一下这一路学习我个人发现的在办公.编程或者学新知识等方面针对 ...

  2. 在django中如何从零开始搭建一个mock服务

    mock概念 mock 就是模拟接口返回的一系列数据,用自定义的数据替换接口实际需要返回的数据,通过自定义的数据来实现对下级接口模块的测试.这里分为两类测试:一类是前端对接口的mock,一类是后端单元 ...

  3. 学习方法,学习方式By:ラピスラズリ(Dawn)20200407

    原创,转载请注明,谢谢!

  4. Linux - Ubuntu18.04下更改apt源为阿里云源

    进入apt目录,备份原来的源地址 cd /etc/apt mv ./source.list ./source.list.bak 修改源文件source.list vim source.list 更换阿 ...

  5. 【WPF学习】第六十四章 构建基本的用户控件

    创建一个简单用户控件是开始自定义控件的好方法.本章主要介绍创建一个基本的颜色拾取器.接下来分析如何将这个控件分解成功能更强大的基于模板的控件. 创建基本的颜色拾取器很容易.然而,创建自定义颜色拾取器仍 ...

  6. 1027 Colors in Mars (20 分)

    People in Mars represent the colors in their computers in a similar way as the Earth people. That is ...

  7. 数据挖掘-K-近邻算法

    数据挖掘-K-近邻算法 目录 数据挖掘-K-近邻算法 1. K-近邻算法概述 1.1 K-近邻算法介绍 1.1.1 KNN算法作用 1.1.2 KNN 算法思想 1.1.3 KNN算法特点 1.2 K ...

  8. thinkphp后端开发ajax接口开发测试(2)

    非常好用的Postman,Google chrome上必备测试ajax接口插件:

  9. Ubuntu16.04默认Python3.5升级Python3.6踩坑

    好久没更新博客了,每天还是踩坑中.今天遇到第一个问题“ImportError: No module named 'secrets'”,导包是常见问题.这次的问题导致我又重装了一次环境,不过这是一个新服 ...

  10. docker下安装centos,并在其上搭建lnmp环境

    一.安装CentOs容器 1.进入docker下载CentOs,这里我使用的CentOs6.8 docker pull centos:6.8 2.创建容器 sudo docker run --priv ...