CyclicBarrier原来是这样的
上一篇聊了一下Semaphore信号灯的用法及源码,这一篇来聊一下CyclicBarrier的用法及解析。
官网解释:
- 允许一组线程全部等待彼此达到共同屏障点的同步辅助。循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。屏障被称为循环 ,因为它可以在等待的线程被释放之后重新使用。
意思就是每个线程都得执行到等待点进行等待,直到所有线程都执行到等待点,才会继续往下执行。相当于日常开会,只有等每个参会的人都到之后才会开始会议。

用法:(以开会举例)
1、会议需要三个人
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new Runnable() {
@Override
public void run()
2、这是三个人都到齐之后会执行的代码
System.out.println("三个人都已到达会议室")
}
}); 3、定义三个线程,相当于三个参会的人
for (int i = 0; i < 3; i++) {
final int finalI = i;
new Thread(new Runnable() {
@Override
public void run() {
try {
4、模拟每人到会议室所需时间
Thread.sleep((long) (Math.random()*5000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第"+Thread.currentThread().getName()+"个人到达会议室");
try {
5、等待其他人到会议室
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"开始开会");
}
}, String.valueOf(finalI)).start();
}
上述代码运行的结果为:

源码解析:
一、构造方法

有两个构造方法,只有带Runnable参数的构造方法才会在所有线程都到达等待点之后执行Runnable里面的run方法。
CyclicBarrier(int parties) {
this(parties, null);
}
CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
二、维护锁状态逻辑
其底层使用ReentrantLock+Condition进行锁状态的维护
1、维护锁状态
private final ReentrantLock lock = new ReentrantLock();
private final Condition trip = lock.newCondition();
2、线程组数
private final int parties;
3、所有线程到达等待点后执行的Runnable
private final Runnable barrierCommand;
4、需要等待的线程数量
private int count;
6、屏障点定义
private static class Generation {
boolean broken = false;
}
具体看看其是如何实现等待逻辑的,线程等待需要调用await方法
public int await() {
return dowait(false, 0L);
}
public int await(long timeout, TimeUnit unit){
return dowait(true, unit.toNanos(timeout));
}
最终调用的是dowait方法
private int dowait(boolean timed, long nanos){
final ReentrantLock lock = this.lock;
1、获取锁
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
2、如果线程中断,重置等待线程数量并且唤醒当前等待的线程
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
3、等待线程数减1
int index = --count;
4、当等待线程数为 时
if (index == 0) { // tripped
boolean ranAction = false;
try {
5、执行所有线程都到达等待点之后的Runnable
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
6、唤醒所有线程并生成下一代
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
7、如果等待线程数不为0
for (;;) {
try {
8、根据传入的参数来决定是定时等待还是非定时等待
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
9、线程中断之后唤醒所有线程并进入下一代
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
Thread.currentThread().interrupt();
}
}
10、如果线程因为打翻屏障操作而被唤醒则抛出异常
if (g.broken)
throw new BrokenBarrierException();
11、如果线程因为换代操作而被唤醒则返回计数器的值
if (g != generation)
return index;
12、如果线程因为时间到了而被唤醒则打翻栅栏并抛出异常
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
可以看到,是通过index字段控制线程等待的,当index不为0的时候,线程统一会进行阻塞,直到index为0的时候,才会唤醒所有线程,这时候所有线程才会继续往下执行。
三、重复使用
这个跟CountdownLatch不一样的是,CountdownLatch是一次性的,而CycliBarrier是可以重复使用的,只需调用一下reset方法。
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
1、破坏当前的屏障点并唤醒所有线程
breakBarrier();
2、生成下一代
nextGeneration();
} finally {
lock.unlock();
}
}
private void breakBarrier() {
generation.broken = true;
将等待线程数量重置
count = parties;
唤醒所有线程
trip.signalAll();
}
private void nextGeneration() {
唤醒所有线程
trip.signalAll();
将等待线程数量重置
count = parties;
generation = new Generation();
}
上述就是对CycliBarrier的解析。
=======================================================
我是Liusy,一个喜欢健身的程序员。
CyclicBarrier原来是这样的的更多相关文章
- 【Java并发编程实战】-----“J.U.C”:CyclicBarrier
在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...
- 多线程条件通行工具——CyclicBarrier
CyclicBarrier的作用是,线程进入等待后,需要达到一定数量的等待线程后,再一次性开放通行. CyclicBarrier(int, Runnable)构造方法,参数1为通行所需的线程数量,参数 ...
- java多线程--同步屏障CyclicBarrier的使用
CyclicBarrier的概念理解: CyclicBarrier的字面上的意思是可循环的屏障,是java并发包java.util.concurrent 里的一个同步工具类,在我下载的JDK1.6的中 ...
- 架构师养成记--12.Concurrent工具类CyclicBarrier和CountDownLatch
java.util.concurrent.CyclicBarrier 一组线程共同等待,直到达到一个公共屏障点. 举个栗子,百米赛跑中,所有运动员都要等其他运动员都准备好后才能一起跑(假如没有发令员) ...
- java并发编程(十九)障碍器CyclicBarrier
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17512983 CyclicBarrier(又叫障碍器)同样是Java 5中加入的新特性,使 ...
- Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例
概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...
- 【JUC】JDK1.8源码分析之CyclicBarrier(四)
一.前言 有了前面分析的基础,现在,接着分析CyclicBarrier源码,CyclicBarrier类在进行多线程编程时使用很多,比如,你希望创建一组任务,它们并行执行工作,然后在进行下一个步骤之前 ...
- CyclicBarrier ------仿真赛马游戏
import java.util.ArrayList;import java.util.List;import java.util.Random;import java.util.concurrent ...
- java并发编程学习:如何等待多个线程执行完成后再继续后续处理(synchronized、join、FutureTask、CyclicBarrier)
多线程应用中,经常会遇到这种场景:后面的处理,依赖前面的N个线程的处理结果,必须等前面的线程执行完毕后,后面的代码才允许执行. 在我不知道CyclicBarrier之前,最容易想到的就是放置一个公用的 ...
- CountDownLatch和CyclicBarrier 举例详解
有时候会有这样的需求,多个线程同时工作,然后其中几个可以随意并发执行,但有一个线程需要等其他线程工作结束后,才能开始.举个例子,开启多个线程分块下载一个大文件,每个线程只下载固定的一截,最后由另外一个 ...
随机推荐
- node中间件
npm i body-parser post 请求主题中间件 const bodyParser = require('body-parser') const bodyParser = requir ...
- linux 安装ifconfig
一:使用yum命令下载安装wget 查看镜像中ifconfig安装包 yum search ifconfig yum install net-tools.x86_64 -y 下面按照提示一步步安装即可 ...
- leetcode刷题-66加一
题目 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. 示例 1: ...
- leetcode刷题-58最后一个单词
题目 给定一个仅包含大小写字母和空格 ' ' 的字符串 s,返回其最后一个单词的长度.如果字符串从左向右滚动显示,那么最后一个单词就是最后出现的单词. 如果不存在最后一个单词,请返回 0 . 说明:一 ...
- SpringMVC-Controller&RestFul
Controller与RestFul 目录 Controller与RestFul 1. Controller 1. 控制器Controller 2. 利用接口定义控制器 1. 实现Controller ...
- Echars 参数说明
theme = { // 全图默认背景 // backgroundColor: 'rgba(0,0,0,0)', // 默认色板 color: ['#ff7f50','#87cefa','#da70d ...
- 感知生命周期的数据 -- LiveData
感知生命周期的数据 -- LiveData 零. 前言 上篇文章<万物基于Lifecycle> 介绍了整个Lifecycle体系的基石,今天这篇文章咱们来看看Jetpack给我们带来的活着 ...
- linux下设置账户锁定阈值:登录失败n次,多长时间后解锁重新登录
在centos系统下: 1.执行命令 vim /etc/pam.d/system-auth或vim /etc/pam.d/ login 2.执行命令 vim /etc/pam.d/sshd 3.在上面 ...
- Java面试必问之-JUC
JUC:java.util.concurrent (Java并发编程工具类) 代码:D:\JAVA\Java_Learning\Elipse_Project\workspace200301EE\JUC ...
- 软件工程与UML作业2
博客班级 https://edu.cnblogs.com/campus/fzzcxy/2018SE1 作业要求 https://edu.cnblogs.com/campus/fzzcxy/2018SE ...