CyclicBarrier分析
简介
- CyclicBarrier 是什么?
- CyclicBarrier 使用
- CyclicBarrier 源码解析
- CyclicBarrier 简单实现
- barrierAction 是由哪个线程执行的?
CyclicBarrier 是什么?
CyclicBarrier 开始于JDK 1.5, 一个同步工具类,允许一组线程都等待彼此到达公共屏障点。CyclicBarrier 在程序中非常有用,涉及到固定参数的线程数量等待彼此,这个 barrier 被称为
cyclic 是由于它可以所有的等待线程释放之后,重复使用。
CyclicBarrier 支持一个可选的 Runnable 在每一个屏障点执行一次,在所有参与的线程到达之后,但是在执行之前所有的线程都释放了, barrierAction非常有用的对于在任何参与者继续之前更新共享状态。
CyclicBarrier 使用
public class Test2 {
static class A extends Thread {
private CyclicBarrier cyclicBarrier;
public A(CyclicBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 准备完毕");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
static class B extends Thread {
private CyclicBarrier cyclicBarrier;
public B(CyclicBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 准备完毕");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
static class C extends Thread {
private CyclicBarrier cyclicBarrier;
public C(CyclicBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 准备完毕");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> System.out.println("完成"));
new A(cyclicBarrier, "A").start();
new B(cyclicBarrier, "B").start();
new C(cyclicBarrier, "C").start();
}
}
/**
output:
A 准备完毕
B 准备完毕
C 准备完毕
完成
*/
CyclicBarrier 源码解析
在看源码前,我们可以对源码的实现进行一些猜想,根据 CyclicBarrier 前面的定义,可以猜想里面有一个变量来表示参与者的数量,在使用调用 await 方法是时候,参与者的数量减一,
知道参与者数量为 0,存在 barrierAction,就执行barrierAction,由于可以重复使用,所以在barrierAction执行对参与者的数量进行恢复。
下面看一下源码实现是否于猜想的类似。
构造方法
parties 参与者的数量
barrierAction 最后执行的动作(可选)
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;
}
await 方法
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
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;
// 如果参与者数量为0,判断barrierAction是否为null,不为null, 将执行run方法,调用nextGeneration恢复状态
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
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;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
nextGeneration 方法
private void nextGeneration() {
// signal completion of last generation
trip.signalAll(); // 唤醒参与者
// set up next generation
count = parties; // 恢复参与者的数量
generation = new Generation(); // 下一代
}
CyclicBarrier 简单实现
借助AtomicInteger 来简单实现
public class SimpleBarrier {
private AtomicInteger count;
int size;
private Runnable command;
public SimpleBarrier(int n) {
this.count = new AtomicInteger(n);
this.size = n;
}
public SimpleBarrier(int n, Runnable barrierAction) {
this(n);
this.command = barrierAction;
}
public void await() {
int position = count.getAndDecrement();
if (position == 1) {
command.run();
count.set(size);
} else {
while (count.get() != 0) {
}
}
}
}
public class Test2 {
static class A extends Thread {
private SimpleBarrier cyclicBarrier;
public A(SimpleBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 准备完毕");
cyclicBarrier.await();
}
}
static class B extends Thread {
private SimpleBarrier cyclicBarrier;
public B(SimpleBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 准备完毕");
cyclicBarrier.await();
}
}
static class C extends Thread {
private SimpleBarrier cyclicBarrier;
public C(SimpleBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
setName(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 准备完毕");
cyclicBarrier.await();
}
}
public static void main(String[] args) {
SimpleBarrier cyclicBarrier = new SimpleBarrier(3, () -> System.out.println("完成"));
new A(cyclicBarrier, "A").start();
new B(cyclicBarrier, "B").start();
new C(cyclicBarrier, "C").start();
}
}
/**
output:
A 准备完毕
B 准备完毕
C 准备完毕
完成
*/
barrierAction 是由哪个线程执行的?
最后一个线程来执行。
CyclicBarrier分析的更多相关文章
- CyclicBarrier分析与实例
一,介绍 CyclicBarrier是一个保持多个线程共享同一个状态的工具类. 也就是说在多线程环境下,能够通过设定某一个状态来达到线程之间的同步.这个类有两个有參构造方法.各自是CyclicBar ...
- 【Java并发编程实战】-----“J.U.C”:CyclicBarrier
在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...
- 【JUC】JDK1.8源码分析之CyclicBarrier(四)
一.前言 有了前面分析的基础,现在,接着分析CyclicBarrier源码,CyclicBarrier类在进行多线程编程时使用很多,比如,你希望创建一组任务,它们并行执行工作,然后在进行下一个步骤之前 ...
- Java 线程同步组件 CountDownLatch 与 CyclicBarrier 原理分析
1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个线程同步 ...
- 并发编程(七)——AbstractQueuedSynchronizer 之 CountDownLatch、CyclicBarrier、Semaphore 源码分析
这篇,我们的关注点是 AQS 最后的部分,共享模式的使用.本文先用 CountDownLatch 将共享模式说清楚,然后顺着把其他 AQS 相关的类 CyclicBarrier.Semaphore 的 ...
- Java并发编程笔记之CyclicBarrier源码分析
JUC 中 回环屏障 CyclicBarrier 的使用与分析,它也可以实现像 CountDownLatch 一样让一组线程全部到达一个状态后再全部同时执行,但是 CyclicBarrier 可以被复 ...
- 【JUC】JDK1.8源码分析之CyclicBarrier
一.前言 有了前面分析的基础,现在,接着分析CyclicBarrier源码,CyclicBarrier类在进行多线程编程时使用很多,比如,你希望创建一组任务,它们并行执行工作,然后在进行下一个步骤之前 ...
- 并发编程之 CyclicBarrier 源码分析
前言 在之前的介绍 CountDownLatch 的文章中,CountDown 可以实现多个线程协调,在所有指定线程完成后,主线程才执行任务. 但是,CountDownLatch 有个缺陷,这点 JD ...
- Java - "JUC" CyclicBarrier源码分析
Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例 CyclicBarrier简介 CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 ...
随机推荐
- 15. Vue2.4+新增属性.sync
.sync 在vue2.4以前,父组件向子组件传值用props:子组件不能直接更改父组件传入的值,需要通过$emit触发自定义事件,通知父组件改变后的值. 父组件: <template> ...
- Day09_41_集合_Set
Set集合 Set集合 - Set集合的特点是无序不可重复.Set集合类似于一个罐子,程序可以依次把多个对象"丢进"Set集合,而Set集合通常不能记住元素的添加顺序. - Set ...
- 基于MATLAB的手写公式识别(5)
基于MATLAB的手写公式识别 总结一下昨天一天的工作成果: 获得了大致的识别过程. 一个图像从生肉到可以被处理需要经过预处理(灰质化.增加对比度.中值过滤.膨胀或腐蚀.闭环运算). 掌握了相关函数的 ...
- Zabbix页面管理
Zabbix页面管理 Screen Screen翻译成中文为"屏幕",在一些交通管理中心.保安监控.预警中心等等地方都比较常见到监控视频,视频上有多块小视频,实际上Zabbix S ...
- 多指灵巧手MoveIt!与Gazebo联合仿真框架搭建
至于为什么叫框架,一是因为灵巧手的3维模型没有按照基本的设计要求画,正常来说,设计机器人机构之前应该设计好机构需要多少个自由度/DOF,每个自由度是旋转/revolute类型还是滑移/prismati ...
- 请解释Spring事务传播传播行为
什么叫事务传播行为? 听起来挺高端的,其实很简单. 即然是传播,那么至少有两个东西,才可以发生传播.单体不不存在传播这个行为. 事务传播行为(propagation behavior)指的就是当一个事 ...
- 路由器逆向分析------MIPS系统网络的配置(QEMU)
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/69378333 MIPS系统网络的配置 使用QEMU 模拟正在运行的MIPS系统并 ...
- Linux中的DHCP服务
目录 DHCP DHCP的报文类型 DHCP的部署 DHCP中继(DHCP代理) DHCP DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一个局 ...
- POJ3070矩阵快速幂简单题
题意: 求斐波那契后四位,n <= 1,000,000,000. 思路: 简单矩阵快速幂,好久没刷矩阵题了,先找个最简单的练练手,总结下矩阵推理过程,其实比较简单,关键 ...
- UVA11462年龄排序
题意: 给你200w个人的年龄,年龄的范围是1-100,然后让你从小到大排序输出所有人的年龄,题目还特意强调输入文件限制25MB,题目内存限制2MB. 思路: 比较经典又简单的一 ...