CyclicBarrier介绍

CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

注意比较CountDownLatch和CyclicBarrier:

(01) CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。

(02) CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。

uml类图

CyclicBarrier是包含了”ReentrantLock对象lock”和”Condition对象trip”,它是通过独占锁实现的。下面通过源码去分析到底是如何实现的。

CyclicBarrier源码分析

1. 构造函数

CyclicBarrier的构造函数共2个:CyclicBarrier 和 CyclicBarrier(int parties, Runnable barrierAction)。第1个构造函数是调用第2个构造函数来实现的,下面第2个构造函数的源码。

public CyclicBarrier(int parties, Runnable barrierAction) {if (parties <= 0) throw new IllegalArgumentException();// parties表示“必须同时到达barrier的线程个数”。this.parties = parties;// count表示“处在等待状态的线程个数”。this.count = parties;// barrierCommand表示“parties个线程到达barrier时,会执行的动作”。this.barrierCommand = barrierAction;
}

2.await函数

public int await() throws InterruptedException, BrokenBarrierException {try {return dowait(false, 0L);} catch (TimeoutException toe) {throw new Error(toe); // cannot happen;}
}

await()是通过dowait()实现的。

private int dowait(boolean timed, long nanos)throws InterruptedException, BrokenBarrierException,TimeoutException {final ReentrantLock lock = this.lock;// 获取“独占锁(lock)”lock.lock();try {// 保存“当前的generation”final Generation g = generation;// 若“当前generation已损坏”,则抛出异常。if (g.broken)throw new BrokenBarrierException();// 如果当前线程被中断,则通过breakBarrier()终止CyclicBarrier,唤醒CyclicBarrier中所有等待线程。if (Thread.interrupted()) {breakBarrier();throw new InterruptedException();}// 将“count计数器”-1int index = --count;// 如果index=0,则意味着“有parties个线程到达barrier”。if (index == 0) {  // trippedboolean ranAction = false;try {// 如果barrierCommand不为null,则执行该动作。final Runnable command = barrierCommand;if (command != null)command.run();ranAction = true;// 唤醒所有等待线程,并更新generation。nextGeneration();return 0;} finally {if (!ranAction)breakBarrier();}}// 当前线程一直阻塞,直到“有parties个线程到达barrier” 或 “当前线程被中断” 或 “超时”这3者之一发生,// 当前线程才继续执行。for (;;) {try {// 如果不是“超时等待”,则调用awati()进行等待;否则,调用awaitNanos()进行等待。if (!timed)trip.await();else if (nanos > 0L)nanos = trip.awaitNanos(nanos);} catch (InterruptedException ie) {// 如果等待过程中,线程被中断,则执行下面的函数。if (g == generation && ! g.broken) {breakBarrier();throw ie;} else {Thread.currentThread().interrupt();}}// 如果“当前generation已经损坏”,则抛出异常。if (g.broken)throw new BrokenBarrierException();// 如果“generation已经换代”,则返回index。if (g != generation)return index;// 如果是“超时等待”,并且时间已到,则通过breakBarrier()终止CyclicBarrier,唤醒CyclicBarrier中所有等待线程。if (timed && nanos <= 0L) {breakBarrier();throw new TimeoutException();}}} finally {// 释放“独占锁(lock)”lock.unlock();}
}

说明:dowait()的作用就是让当前线程阻塞,直到“有parties个线程到达barrier” 或 “当前线程被中断” 或 “超时”这3者之一发生,当前线程才继续执行。

(01) generation是CyclicBarrier的一个成员遍历,它的定义如下:

private Generation generation = new Generation();private static class Generation {boolean broken = false;
}

在CyclicBarrier中,同一批的线程属于同一代,即同一个Generation;CyclicBarrier中通过generation对象,记录属于哪一代。
当有parties个线程到达barrier,generation就会被更新换代。

(02) 如果当前线程被中断,即Thread.interrupted()为true;则通过breakBarrier()终止CyclicBarrier。breakBarrier()的源码如下:

private void breakBarrier() {generation.broken = true;count = parties;trip.signalAll();
}

breakBarrier()会设置当前中断标记broken为true,意味着“将该Generation中断”;同时,设置count=parties,即重新初始化count;最后,通过signalAll()唤醒CyclicBarrier上所有的等待线程。

(03) 将“count计数器”-1,即–count;然后判断是不是“有parties个线程到达barrier”,即index是不是为0。
当index=0时,如果barrierCommand不为null,则执行该barrierCommand,barrierCommand就是我们创建CyclicBarrier时,传入的Runnable对象。然后,调用nextGeneration()进行换代工作,nextGeneration()的源码如下:

private void nextGeneration() {trip.signalAll();count = parties;generation = new Generation();
}

首先,它会调用signalAll()唤醒CyclicBarrier上所有的等待线程;接着,重新初始化count;最后,更新generation的值。

(04) 在for(;;)循环中。timed是用来表示当前是不是“超时等待”线程。如果不是,则通过trip.await()进行等待;否则,调用awaitNanos()进行超时等待。

CyclicBarrier使用例子

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.BrokenBarrierException;public class CyclicBarrierTest1 {private static int SIZE = 5;private static CyclicBarrier cb;public static void main(String[] args) {cb = new CyclicBarrier(SIZE);// 新建5个任务for(int i=0; i<SIZE; i++)new InnerThread().start();}static class InnerThread extends Thread{public void run() {try {System.out.println(Thread.currentThread().getName() + " wait for CyclicBarrier.");// 将cb的参与者数量加1cb.await();// cb的参与者数量等于5时,才继续往后执行System.out.println(Thread.currentThread().getName() + " continued.");} catch (BrokenBarrierException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}}
}

运行结果:

Thread-1 wait for CyclicBarrier.
Thread-2 wait for CyclicBarrier.
Thread-3 wait for CyclicBarrier.
Thread-4 wait for CyclicBarrier.
Thread-0 wait for CyclicBarrier.
Thread-0 continued.
Thread-4 continued.
Thread-2 continued.
Thread-3 continued.
Thread-1 continued.

结果说明:主线程中新建了5个线程,所有的这些线程都调用cb.await()等待。所有这些线程一直等待,直到cb中所有线程都达到barrier时,这些线程才继续运行!

例子2:

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.BrokenBarrierException;public class CyclicBarrierTest2 {private static int SIZE = 5;private static CyclicBarrier cb;public static void main(String[] args) {cb = new CyclicBarrier(SIZE, new Runnable () {public void run() {System.out.println("CyclicBarrier's parties is: "+ cb.getParties());}});// 新建5个任务for(int i=0; i<SIZE; i++)new InnerThread().start();}static class InnerThread extends Thread{public void run() {try {System.out.println(Thread.currentThread().getName() + " wait for CyclicBarrier.");// 将cb的参与者数量加1cb.await();// cb的参与者数量等于5时,才继续往后执行System.out.println(Thread.currentThread().getName() + " continued.");} catch (BrokenBarrierException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}}
}

运行结果:

Thread-1 wait for CyclicBarrier.
Thread-2 wait for CyclicBarrier.
Thread-3 wait for CyclicBarrier.
Thread-4 wait for CyclicBarrier.
Thread-0 wait for CyclicBarrier.
CyclicBarrier's parties is: 5
Thread-0 continued.
Thread-4 continued.
Thread-2 continued.
Thread-3 continued.
Thread-1 continued.

JUC锁-CyclicBarrier(七)相关推荐

  1. Java多线程系列---“JUC锁”01之 框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下: 01. Java多线程系列--"JUC锁"01之 框架 02. Java多线程系列--"JUC锁 ...

  2. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对"公平锁"的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括: 基本概念 ReentrantLock数据结构 参考代码 获取公平锁(基于JDK1.7.0 ...

  3. Java多线程系列--“JUC锁”05之 非公平锁

    转载自:http://www.cnblogs.com/skywang12345/p/3496651.html点击打开链接 概要 前面两章分析了"公平锁的获取和释放机制",这一章开始 ...

  4. JUC锁框架AbstractQueuedSynchronizer详细分析

    转载自:https://www.jianshu.com/p/0da2939391cf AQS是JUC锁框架中最重要的类,通过它来实现独占锁和共享锁的.本章是对AbstractQueuedSynchro ...

  5. JUC锁框架_AbstractQueuedSynchronizer详细分析

    AQS是JUC锁框架中最重要的类,通过它来实现独占锁和共享锁的.本章是对AbstractQueuedSynchronizer源码的完全解析,分为四个部分介绍: CLH队列即同步队列:储存着所有等待锁的 ...

  6. JUC锁框架——AQS源码分析

    2019独角兽企业重金招聘Python工程师标准>>> JUC锁介绍 Java的并发框架JUC(java.util.concurrent)中锁是最重要的一个工具.因为锁,才能实现正确 ...

  7. JUC锁框架——CyclicBarrier

    2019独角兽企业重金招聘Python工程师标准>>> CyclicBarrier的简单介绍 CyclicBarrier是一个同步辅助类,它允许一组线程相互等待,直到到达某个公共屏障 ...

  8. Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

    CyclicBarrier简介 CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).因为该 barrier 在释放等 ...

  9. 并发编程JUC深度学习(七)无锁(乐观锁)

    前言 乐观锁总是假设最好的情况,每次去拿数据的时候都认为数据不会被修改,所以不会上锁,只是在更新的时候会判断一下在这期间别人有没有去更新这个数据,主要是由版本号机制和CAS算法实现,这里我们主要介绍C ...

最新文章

  1. 青少年电子信息智能创新大赛 赛项说明(Python编程创新挑战赛)
  2. fatal error LNK1103: debugging information corrupt; recompile module
  3. NHibernate初探-SQLDialects
  4. python如何获取请求的url_听说你在学习:如何通过代码请求URL地址
  5. class ts 扩展方法_一个class文件到底包含了哪些东西?
  6. 华为发布全新一代OceanStor存储Pacific系列,打造海量数据存储新标杆
  7. Activiti工作流Day18-Crystalball流程仿真
  8. 三因子两水平doe_minitab doe 操作说明 范例 全因子实验设计法3 因子2 水平实验设计.pdf...
  9. 常用DB9外设接口定义
  10. npm和包、npm下载安装使用包、全局安装包和本地安装包、全局安装nodemon包、开发依赖和生产依赖
  11. u盘修复计算机w7,制作win7系统修复u盘的方法
  12. 高等数学学习笔记——第八讲——数列极限的性质(2.数列极限的四则运算法则)
  13. Godaddy上的域名如何取消自动续费?
  14. [渝粤教育] 上海交通大学 流体力学 参考 资料
  15. 滚动的gridview
  16. python 读文件 如何从第二行开始
  17. Kubernetes 版本升级
  18. vue 中的indexof_vue的这段排序代码看着不是很懂, p = p.name.indexOf(searchperson)!== -1到底是什么意思...
  19. linux 分区id,分区ID对照表和diskpart更改分区ID的方法
  20. 初步实现使用pppd连接GPRS上网

热门文章

  1. 漫游Kafka实现篇之消息和日志
  2. 端口复用突破防火墙(图)
  3. GStreamer 的调试工具
  4. 如何预编译 Android 模拟器专用内核
  5. 视频质量评估的新方式:VMAF百分位数
  6. 【教育与多媒体技术】
  7. 音视频技术开发周刊 53期
  8. 观察:谁能拯救视频平台的高昂带宽成本?
  9. 利用Simple-RTMP-Server搭建RTMP和HLS直播服务(上)
  10. 大牛书单 | 消息队列方向的好书