java中CyclicBarrier的使用

CyclicBarrier是java 5中引入的线程安全的组件。它有一个barrier的概念,主要用来等待所有的线程都执行完毕,然后再去执行特定的操作。

假如我们有很多个线程,每个线程都计算出了一些数据,然后我们需要等待所有的线程都执行完毕,再把各个线程计算出来的数据加起来,的到最终的结果,那么我们就可以使用CyclicBarrier。

CyclicBarrier的方法

我们先看下CyclicBarrier的构造函数:

  1. public CyclicBarrier(int parties, Runnable barrierAction) {
  2. if (parties <= 0) throw new IllegalArgumentException();
  3. this.parties = parties;
  4. this.count = parties;
  5. this.barrierCommand = barrierAction;
  6. }
  7. public CyclicBarrier(int parties) {
  8. this(parties, null);
  9. }

CyclicBarrier有两个构造函数,第一个只接受一个参数,表示需要统一行动的线程个数。第二个参数叫做barrierAction,表示出发barrier是需要执行的方法。

其中barrierAction是一个Runnable,我们可以在其中定义最后需要执行的工作。

再看下重要await方法:

  1. public int await() throws InterruptedException, BrokenBarrierException {
  2. try {
  3. return dowait(false, 0L);
  4. } catch (TimeoutException toe) {
  5. throw new Error(toe); // cannot happen
  6. }
  7. }
  8. public int await(long timeout, TimeUnit unit)
  9. throws InterruptedException,
  10. BrokenBarrierException,
  11. TimeoutException {
  12. return dowait(true, unit.toNanos(timeout));
  13. }

await也有两个方法,一个是带时间参数的,一个是不带时间参数的。

await本质上调用了lock.newCondition().await()方法。

因为有多个parties,下面我们考虑两种情况。

  1. 该线程不是最后一个调用await的线程

在这种情况下,该线程将会进入等待状态,直到下面的情况发送:

  • 最后一个线程调用await()
  • 其他线程中断了当前线程
  • 其他线程中断了其他正在等待的线程
  • 其他线程在等待barrier的时候超时
  • 其他线程在该barrier上调用的reset()方法

如果该线程在调用await()的时候已经设置了interrupted的状态,或者在等待的时候被interrupted,那么将会抛出InterruptedException异常,并清除中断状态。(这里和Thread的interrupt()方法保持一致)

如果任何线程正在等待状态中,这时候barrier被重置。或者在线程调用await方法或者正在等待中,barrier被broken,那么将会抛出BrokenBarrierException。

如果任何线程在等待的时候被中断,那么所有其他等待的线程将会抛出BrokenBarrierException,barrier将会被置为broken状态。

  1. 如果该线程是最后一个调用await方法的

在这种情况,如果barrierAction不为空,那么该线程将会在其他线程继续执行前调用这个barrierAction。

如果该操作抛出异常,那么barrier的状态将会被置为broken状态。

再看看这个reset() 方法:

  1. public void reset() {
  2. final ReentrantLock lock = this.lock;
  3. lock.lock();
  4. try {
  5. breakBarrier(); // break the current generation
  6. nextGeneration(); // start a new generation
  7. } finally {
  8. lock.unlock();
  9. }
  10. }

该方法将会将barrier置为broken状态,并且开启一个新的generation,来进行下一轮的操作。

CyclicBarrier的使用

我们在子线程中生成一个随机的整数队列,当所有的线程都生成完毕之后,我们再将生成的整数全都加起来。看下怎么实现。

定义生成整数队列的子线程:

  1. public class CyclicBarrierUsage implements Runnable {
  2. private CyclicBarrier cyclicBarrier;
  3. private List<List<Integer>> partialResults;
  4. private Random random = new Random();
  5. public CyclicBarrierUsage(CyclicBarrier cyclicBarrier,List<List<Integer>> partialResults){
  6. this.cyclicBarrier=cyclicBarrier;
  7. this.partialResults=partialResults;
  8. }
  9. @Override
  10. public void run() {
  11. String thisThreadName = Thread.currentThread().getName();
  12. List<Integer> partialResult = new ArrayList<>();
  13. // Crunch some numbers and store the partial result
  14. for (int i = 0; i < 10; i++) {
  15. Integer num = random.nextInt(10);
  16. System.out.println(thisThreadName
  17. + ": Crunching some numbers! Final result - " + num);
  18. partialResult.add(num);
  19. }
  20. partialResults.add(partialResult);
  21. try {
  22. System.out.println(thisThreadName
  23. + " waiting for others to reach barrier.");
  24. cyclicBarrier.await();
  25. } catch (InterruptedException e) {
  26. // ...
  27. } catch (BrokenBarrierException e) {
  28. // ...
  29. }
  30. }
  31. }

上面的子线程接收外部传入的cyclicBarrier和保存数据的partialResults,并在运行完毕调用cyclicBarrier.await()来等待其他线程执行完毕。

看下CyclicBarrier的构建:

  1. CyclicBarrier cyclicBarrier=new CyclicBarrier(5,()->{
  2. String thisThreadName = Thread.currentThread().getName();
  3. System.out.println(
  4. thisThreadName + ": Computing sum of 5 workers, having 10 results each.");
  5. int sum = 0;
  6. for (List<Integer> threadResult : partialResults) {
  7. System.out.print("Adding ");
  8. for (Integer partialResult : threadResult) {
  9. System.out.print(partialResult+" ");
  10. sum += partialResult;
  11. }
  12. System.out.println();
  13. }
  14. System.out.println(thisThreadName + ": Final result = " + sum);
  15. });

在CyclicBarrier中,我们定义了一个BarrierAction来做最后数据的汇总处理。

运行:

  1. for (int i = 0; i < 5; i++) {
  2. Thread worker = new Thread(new CyclicBarrierUsage(cyclicBarrier,partialResults));
  3. worker.setName("Thread " + i);
  4. worker.start();
  5. }

输出结果如下:

  1. Spawning 5 worker threads to compute 10 partial results each
  2. Thread 0: Crunching some numbers! Final result - 5
  3. Thread 0: Crunching some numbers! Final result - 3
  4. Thread 1: Crunching some numbers! Final result - 1
  5. Thread 0: Crunching some numbers! Final result - 7
  6. Thread 1: Crunching some numbers! Final result - 8
  7. Thread 0: Crunching some numbers! Final result - 4
  8. Thread 0: Crunching some numbers! Final result - 6
  9. Thread 0: Crunching some numbers! Final result - 9
  10. Thread 1: Crunching some numbers! Final result - 3
  11. Thread 2: Crunching some numbers! Final result - 1
  12. Thread 0: Crunching some numbers! Final result - 0
  13. Thread 2: Crunching some numbers! Final result - 9
  14. Thread 1: Crunching some numbers! Final result - 3
  15. Thread 2: Crunching some numbers! Final result - 7
  16. Thread 0: Crunching some numbers! Final result - 2
  17. Thread 2: Crunching some numbers! Final result - 6
  18. Thread 1: Crunching some numbers! Final result - 6
  19. Thread 2: Crunching some numbers! Final result - 5
  20. Thread 0: Crunching some numbers! Final result - 0
  21. Thread 2: Crunching some numbers! Final result - 1
  22. Thread 1: Crunching some numbers! Final result - 5
  23. Thread 2: Crunching some numbers! Final result - 1
  24. Thread 0: Crunching some numbers! Final result - 7
  25. Thread 2: Crunching some numbers! Final result - 8
  26. Thread 1: Crunching some numbers! Final result - 2
  27. Thread 2: Crunching some numbers! Final result - 4
  28. Thread 0 waiting for others to reach barrier.
  29. Thread 2: Crunching some numbers! Final result - 0
  30. Thread 2 waiting for others to reach barrier.
  31. Thread 1: Crunching some numbers! Final result - 7
  32. Thread 1: Crunching some numbers! Final result - 6
  33. Thread 1: Crunching some numbers! Final result - 9
  34. Thread 1 waiting for others to reach barrier.
  35. Thread 3: Crunching some numbers! Final result - 9
  36. Thread 3: Crunching some numbers! Final result - 3
  37. Thread 3: Crunching some numbers! Final result - 8
  38. Thread 3: Crunching some numbers! Final result - 8
  39. Thread 3: Crunching some numbers! Final result - 1
  40. Thread 3: Crunching some numbers! Final result - 8
  41. Thread 3: Crunching some numbers! Final result - 0
  42. Thread 3: Crunching some numbers! Final result - 5
  43. Thread 3: Crunching some numbers! Final result - 9
  44. Thread 3: Crunching some numbers! Final result - 1
  45. Thread 3 waiting for others to reach barrier.
  46. Thread 4: Crunching some numbers! Final result - 2
  47. Thread 4: Crunching some numbers! Final result - 2
  48. Thread 4: Crunching some numbers! Final result - 5
  49. Thread 4: Crunching some numbers! Final result - 5
  50. Thread 4: Crunching some numbers! Final result - 3
  51. Thread 4: Crunching some numbers! Final result - 7
  52. Thread 4: Crunching some numbers! Final result - 4
  53. Thread 4: Crunching some numbers! Final result - 8
  54. Thread 4: Crunching some numbers! Final result - 4
  55. Thread 4: Crunching some numbers! Final result - 3
  56. Thread 4 waiting for others to reach barrier.
  57. Thread 4: Computing sum of 5 workers, having 10 results each.
  58. Adding 5 3 7 4 6 9 0 2 0 7
  59. Adding 1 9 7 6 5 1 1 8 4 0
  60. Adding 1 8 3 3 6 5 2 7 6 9
  61. Adding 9 3 8 8 1 8 0 5 9 1
  62. Adding 2 2 5 5 3 7 4 8 4 3
  63. Thread 4: Final result = 230
  64. Process finished with exit code 0

本文的例子可以参考https://github.com/ddean2009/learn-java-concurrency/tree/master/CyclicBarrier

更多教程请参考 flydean的博客

java中CyclicBarrier的使用的更多相关文章

  1. java中CyclicBarrier简单入门使用

    一个同步辅助类,它同意一组线程互相等待,直到到达某个公共屏障点 (common barrier point). 在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待.此时 CyclicBarr ...

  2. Java中使用CountDownLatch进行多线程同步

    CountDownLatch介绍 在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法: 1.synchronized关键字进行同步. 2.Lock锁接口及其实现类ReentrantL ...

  3. Java中String做为synchronized同步锁使用详解

    Java中使用String作同步锁 在Java中String是一种特殊的类型存在,在jdk中String在创建后是共享常量池的,即使在jdk1.8之后实现有所不同,但是功能还是差不多的. 借助这个特点 ...

  4. java中如何模拟真正的同时并发请求?

    有时需要测试一下某个功能的并发性能,又不要想借助于其他工具,索性就自己的开发语言,来一个并发请求就最方便了. java中模拟并发请求,自然是很方便的,只要多开几个线程,发起请求就好了.但是,这种请求, ...

  5. Java - "JUC" CyclicBarrier源码分析

    Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例 CyclicBarrier简介 CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 ...

  6. 《java并发编程实战》读书笔记4--基础构建模块,java中的同步容器类&并发容器类&同步工具类,消费者模式

    上一章说道委托是创建线程安全类的一个最有效策略,只需让现有的线程安全的类管理所有的状态即可.那么这章便说的是怎么利用java平台类库的并发基础构建模块呢? 5.1 同步容器类 包括Vector和Has ...

  7. Java中的线程--线程中的工具

    这主要想写一下Java中的jdk提供的一些线程中的工具, 一.semaphore信号灯 Semaphore可以维护当前访问自身的线程个数,并提供了同步机制,使用Semaphore可以控制同时访问资源的 ...

  8. java中等待所有线程都执行结束(转)

    转自:http://blog.csdn.net/liweisnake/article/details/12966761 今天看到一篇文章,是关于java中如何等待所有线程都执行结束,文章总结得很好,原 ...

  9. java中等待所有线程都执行结束

    转自:http://blog.csdn.net/liweisnake/article/details/12966761 今天看到一篇文章,是关于java中如何等待所有线程都执行结束,文章总结得很好,原 ...

随机推荐

  1. STM32CubeMX的安装

    1.下载STM32CubeMX 在ST的官方网站上下载STM32CubeMXXX软件的安装包. 下载的安装包如下图所示.双击SetupSTM32CubeMX-5.0.1.exe. 安装STM32Cub ...

  2. 国内 Java 开发者必备的两个装备,你配置上了么?

    虽然目前越来越多的国产优秀技术产品走出了国门,但是对于众领域的开发者来说,依然对于国外的各种基础资源依赖还是非常的强.所以,一些网络基本技能一直都是我们需要掌握的,但是速度与稳定性问题一直也都有困扰着 ...

  3. java对象转为json字符串

    1.使用fastjson开源json工具类库 2.java类未添加get()和set()方法,java对象初始化时,使用fastjson解析,得到的json字符串有时为空{} 3.Java对象转为js ...

  4. 1025 PAT Ranking (25 分)

    Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of Zhe ...

  5. flask-url_for

    flask-url_for flask的url_for函数和django的reverse函数类似,都是提供视图反转url的方法 from flask import Flask, url_for app ...

  6. (js描述的)数据结构[哈希表1.3](10)

    1.哈希表的完善 1.容量质数(limit):需要恒为质数,来确保元素的均匀分布. 1)普通算法: 判断一个数是否为质数 function isPrime(num) { for (var i = 2; ...

  7. Java第一天,带你走进编程的世界,我的第一个程序

    要想彻底了解Java是什么,我就得首先了解编程语言的发展史.编程语言最初的形势是"0101......"数据编程,也就是机器语言.机器语言可以说是一种几乎没有人能够看懂的编程语言, ...

  8. EXPLAIN 关键字可以 查看 sql执行 的详细过程

    EXPLAIN SELECT n_did,n_count,n_total,d_last_exchange FROM player_con_record WHERE n_roleid=1 AND n_f ...

  9. 让图片适合在静态文本控件窗口大小 MFC

    1.加入 IDC_STATIC1 静态文本控件. 2.为文本控件添加 STATIC 型变量 3.在OnInitDialog函数中添加以下代码 //设置该静态控件为显示位图的 m_bitmap.Modi ...

  10. HTTPS工作流程

    HTTPS工作流程 RSA算法 RSA的密钥分成两个部分: PublicKey 加密数据 验证签名 不能解密 任何人都可以获得 Private Key 数据签名(摘要算法) 解密 加密(不用此功能) ...