一种允许多个线程全部等待彼此都到达某个屏障的同步机制

使用

多个线程并发执行同一个CyclicBarrier实例的await方法时,每个线程执行这个方法后,都会被暂停,只有当最后一个线程执行完await方法时,它自身不会暂停,且会唤醒所有等待线程。因为CyclicBarrier内部维护了一个显式锁,它可以识别最后一个执行线程。

CyclicBarrier内部维护一个trip变量来实现等待/通知,所有除最后一个线程的保护条件都是“当前generation中,仍未执行的线程数大于0”,这个仍未执行的线程数默认为总参与线程的数量,await方法每执行一次,这个数量递减1.

使用场景

模拟高并发,或放在一个循环中,使得当前迭代操作的结果作为下一个迭代的基础输入;不然可以直接使用Thread.join()或CoutDwonLatch

问题:

1.可以设置多个屏障吗:可以,以generation区分(cyclic)

示例:
class MyThread extends Thread {
private CyclicBarrier cb;
public MyThread(String name, CyclicBarrier cb) {
super(name);
this.cb = cb;
} public void run() {
System.out.println(Thread.currentThread().getName() + " going to await");
try {
cb.await();
System.out.println(Thread.currentThread().getName() + " continue");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class CyclicBarrierDemo {
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
CyclicBarrier cb = new CyclicBarrier(3, new Thread("barrierAction") {
public void run() {
System.out.println(Thread.currentThread().getName() + " barrier action"); }
});
MyThread t1 = new MyThread("t1", cb);
MyThread t2 = new MyThread("t2", cb);
t1.start();
t2.start();
System.out.println(Thread.currentThread().getName() + " going to await");
cb.await();
System.out.println(Thread.currentThread().getName() + " continue");

}
}

源码阅读

public class CyclicBarrier {
//屏障的每一次使用都代表一代示例
private static class Generation {
//屏障是否被破坏
boolean broken = false;
}
//防止线程跳过屏障的锁 默认非公平锁
private final ReentrantLock lock = new ReentrantLock();
//等待线程跳过屏障的条件
private final Condition trip = lock.newCondition();
//参与线程数量
private final int parties;
//跳过屏障后执行的指令
private final Runnable barrierCommand;
//当前阶段????
private Generation generation = new Generation();
//每一阶段仍在等待的线程
private int count; //barrierAction:跳过屏障后执行的指令
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
//线程到达屏障 则等待:外部等待调用方法
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
/**
* 执行过程:
* 加锁 -> 判断屏障是否被破坏(抛异常) -> 判断线程是否被中断(毁坏屏障,抛异常) ->
* 判断是否仍有等待线程(N -> 执行屏障命令; Y -> 进入屏障等待) -> 解锁
*/
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) { // 全部进入屏障了 执行后续命令
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
//唤醒所有等待线程 进入下一代
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// 自旋直到跳过屏障/中断/超时 停止
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;
//设置了等待时间且时间小于等于0
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
//条件:所有线程处于等待状态
private void nextGeneration() {
// 唤醒所有线程
trip.signalAll();
// 恢复等待线程数
count = parties;
generation = new Generation();
}
}

CyclicBarrier源码阅读的更多相关文章

  1. 《java.util.concurrent 包源码阅读》 结束语

    <java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...

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

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

  3. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  4. 【原】FMDB源码阅读(二)

    [原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...

  5. 【原】FMDB源码阅读(一)

    [原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...

  6. 【原】AFNetworking源码阅读(六)

    [原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...

  7. 【原】AFNetworking源码阅读(五)

    [原]AFNetworking源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中提及到了Multipart Request的构建方法- [AFHTTP ...

  8. 【原】AFNetworking源码阅读(四)

    [原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...

  9. 【原】AFNetworking源码阅读(三)

    [原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...

随机推荐

  1. python的Email提醒

    目的意义 使用Email自动发送,有利于实时获取爬取信息,更方便的掌握要闻. 导入相关库 MINEText库定义了发送信息, Header定义了发送的主题 formate定义了收件人和发件人的格式信息 ...

  2. springMvc接受单个文件,多个文件,多组文件

    web端 <form id="iconForm" enctype="multipart/form-data"></form> JS:通过 ...

  3. [转载]HTTP和HTTPS

    来源:https://blog.csdn.net/xiaoming100001/article/details/81109617 大纲 一.前言: 先来观察这两张图,第一张访问域名http://www ...

  4. Python爬虫 Selenium与PhantomJS

    Selenium Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动化操作,不同是Sele ...

  5. python之json操作

    1.json.dumps()用于将dict类型的数据转成str 备注:文件路径前面加上 r 是为了避免转义 1 import json 2 3 dict = {'a': 'wo', 'b': 'zai ...

  6. vue学习【一】vue引用封装echarts并展示多个echarts图表

    大家好,我是一叶,经过一段时间对vue的学习,我打算把vue做一个系列,把踩过的坑和大家分享一下. 现在开始第一章:vue引用并封装echarts 在文章开始前,我先舔波echarts(真香).阿里的 ...

  7. postgres日常操作

    1.启动pgsl数据库 [postgres@master ~]$ pg_ctl start [postgres@master data]$ pg_ctl -D /usr/local/pgsql/dat ...

  8. MySQL之数据库优化

    Mysql数据库的优化技术 对mysql优化是一个综合性的技术,主要包括 •表的设计合理化(符合3NF) •添加适当索引(index) [四种: 普通索引.主键索引.唯一索引unique.全文索引] ...

  9. (转)java并发编程:CopyOnWriteArrayList

    原文链接:http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容, ...

  10. 第一篇、Python入门

    一 编程与编程语言 python是一门编程语言,作为学习python的开始,需要事先搞明白:编程的目的是什么?什么是编程语言?什么是编程? 编程的目的: #计算机的发明,是为了用机器取代/解放人力,而 ...