简介

  1. CyclicBarrier 是什么?
  2. CyclicBarrier 使用
  3. CyclicBarrier 源码解析
  4. CyclicBarrier 简单实现
  5. 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分析的更多相关文章

  1. CyclicBarrier分析与实例

    一,介绍 ​CyclicBarrier是一个保持多个线程共享同一个状态的工具类. 也就是说在多线程环境下,能够通过设定某一个状态来达到线程之间的同步.这个类有两个有參构造方法.各自是CyclicBar ...

  2. 【Java并发编程实战】-----“J.U.C”:CyclicBarrier

    在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...

  3. 【JUC】JDK1.8源码分析之CyclicBarrier(四)

    一.前言 有了前面分析的基础,现在,接着分析CyclicBarrier源码,CyclicBarrier类在进行多线程编程时使用很多,比如,你希望创建一组任务,它们并行执行工作,然后在进行下一个步骤之前 ...

  4. Java 线程同步组件 CountDownLatch 与 CyclicBarrier 原理分析

    1.简介 在分析完AbstractQueuedSynchronizer(以下简称 AQS)和ReentrantLock的原理后,本文将分析 java.util.concurrent 包下的两个线程同步 ...

  5. 并发编程(七)——AbstractQueuedSynchronizer 之 CountDownLatch、CyclicBarrier、Semaphore 源码分析

    这篇,我们的关注点是 AQS 最后的部分,共享模式的使用.本文先用 CountDownLatch 将共享模式说清楚,然后顺着把其他 AQS 相关的类 CyclicBarrier.Semaphore 的 ...

  6. Java并发编程笔记之CyclicBarrier源码分析

    JUC 中 回环屏障 CyclicBarrier 的使用与分析,它也可以实现像 CountDownLatch 一样让一组线程全部到达一个状态后再全部同时执行,但是 CyclicBarrier 可以被复 ...

  7. 【JUC】JDK1.8源码分析之CyclicBarrier

    一.前言 有了前面分析的基础,现在,接着分析CyclicBarrier源码,CyclicBarrier类在进行多线程编程时使用很多,比如,你希望创建一组任务,它们并行执行工作,然后在进行下一个步骤之前 ...

  8. 并发编程之 CyclicBarrier 源码分析

    前言 在之前的介绍 CountDownLatch 的文章中,CountDown 可以实现多个线程协调,在所有指定线程完成后,主线程才执行任务. 但是,CountDownLatch 有个缺陷,这点 JD ...

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

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

随机推荐

  1. GO-02-helloworld

    package main /** package main表示一个可独立执行的程序,每个Go应用程序都需要包含一个名为main的包, 并且该包包含一个叫main()的函数(该函数是Go可执行程序的执行 ...

  2. 研发团队管理:IT研发中项目和产品原来区别那么大,项目级的项目是项目,产品级的项目是产品!!!

    前言   从事IT行业多年,一路从小杂兵成长为大团队Leader,对于研发整个体系比较清楚,其实大多人都经历过但是都忽略了的研发成本管控的一个关键的点就是研发过程中项目级和产品级的区别.   市场基本 ...

  3. Java 轻松理解深拷贝与浅拷贝

    目录 前言 直接赋值 拷贝 浅拷贝 举例 原理 深拷贝 实现: Serializable 实现深拷贝 总结 前言 本文代码中有用到一些注解,主要是Lombok与junit用于简化代码. 主要是看到一堆 ...

  4. 记canvas画笔笔迹的多次优化过程

    我们的项目是面向学校老师的教学软件,所以肯定少不了互动白板的功能,而这个里面的画笔功能是由我来开发的,下面介绍这个过程中遇到的问题以及解决方法. 首先给大家明确下由于软件中的画布可以自由移动,会超出屏 ...

  5. mvnw 找不到或无法加载主类,找不到符号,类

    如果你出现"找不到或无法加载主类"的问题,很有可能是maven的问题,你可以尝试一下这种办法: 问题:关于maven什么东西都没动,上午可能运行都好好的,下午可能就出现了这个问题, ...

  6. 基于golang分布式爬虫系统的架构体系v1.0

    基于golang分布式爬虫系统的架构体系v1.0 一.什么是分布式系统 分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统.简单来说就是一群独立计算机 ...

  7. Smith Numbers(分解质因数)

    Smith Numbers Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14173   Accepted: 4838 De ...

  8. php 操作 redis 常用命令

    原文地址: https://www.cnblogs.com/zhanghanwen16/p/9510481.html 1.redis连接与认证 //连接参数:ip.端口.连接超时时间,连接成功返回tr ...

  9. LA2678最短子序列

    题意:       给你一个正整数序列,问你在里面找到一个最短的子序列,要求子序列的和大于等于k,输出序列长度. 思路:       这个序列的每个数字都是正整数,那么就比较好想了,我们可以直接枚举终 ...

  10. Windows下包管理工具Bower的安装和使用

    目录 安装Bower Bower的使用 安装Bower Windows下安装Bower之前,先安装好 nodejs 和 msysgit 环境 然后我们就可以使用npm包管理工具下载并全局安装bower ...