【JUC】CyclicBarrier的了解和使用
时间:2022-07-23
本文章向大家介绍【JUC】CyclicBarrier的了解和使用,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
概念
权威指南
- 一种同步辅助工具,它允许一组线程全部互相等待以到达一个公共的障碍点。CyclicBarriers在涉及固定大小的线程方的程序中很有用,该线程方有时必须互相等待。屏障被称为循环屏障, 因为它可以在释放等待线程之后重新使用。
- CyclicBarrier支持可选的Runnable命令,该命令在聚会的最后一个线程到达之后但在释放任何线程之前,每个障碍点运行一次。此屏障操作对于在任何一方继续之前更新共享状态很有用。
个人理解
- 给每个线程设置一个阈值,当每个线程逗达到这个阈值的时候才会去执行。
- 再抽象一点的话,我们去游乐园做船,这个船坐满的时候才会开出去。不坐满的话来的早的人就得等待来的晚的的人。所以这些人也就是会互相等待的。当人坐满的时候才会出发去岛上。这个船还可以重复被使用,当这批人被送走后,还可以承载下一批人。也就是CyclicBarrier的重复使用。
源码
常用方法和构造方法
- 核心源码
- 在CyclicBarrier初始化时,设置栅栏数(new CyclicBarrier( int parties)),每有一个线程执行await方法(用Condition的await阻塞),栅栏就减少一个,直到减少到0,取消等待,唤醒线程(用Condition的signalAll唤醒)
- 任何一个线程被interrupt打断,Condition也会调用signalAll方法唤醒所有阻塞的线程。
- 有reset方法可以还原。(这也是和counDownLatch的最大的区别之一)
- 大概介绍:详细介绍的文章:点击此处
/**
* Main barrier code, covering the various policies.
*/
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();
…………………………………………
}
SHOW ME CODE
package JUC;
import lombok.SneakyThrows;
import java.awt.*;
import java.util.concurrent.CyclicBarrier;
/**
* @authoryuanxindong
* @date: 2020/6/18 11:53 下午
*/
public class CyclicBarrierDemo implements Runnable{
private int timeOut ;
private CyclicBarrier cyclicBarrier;
public void setTimeOut(int timeOut) {
this.timeOut = timeOut;
}
public static class innerCyclicBarrierDemo implements Runnable{
@Override
public void run() {
System.out.println("最后执行的方法+");
}
}
public CyclicBarrierDemo(int timeOut,CyclicBarrier cyclicBarrier) {
this.timeOut = timeOut;
this.cyclicBarrier = cyclicBarrier;
}
public static void main(String[] args) {
// 启用一个CyclicBarrier,然后进行加载。
CyclicBarrier cyclicBarrier =new CyclicBarrier(3,new innerCyclicBarrierDemo());
long startTime = System.currentTimeMillis();
CyclicBarrierDemo cyclicBarrierDemo = new CyclicBarrierDemo(1000,cyclicBarrier);
Thread thread = new Thread(cyclicBarrierDemo);
CyclicBarrierDemo cyclicBarrierDemo2 = new CyclicBarrierDemo(2000,cyclicBarrier);
Thread thread1 = new Thread(cyclicBarrierDemo2);
CyclicBarrierDemo cyclicBarrierDemo3 = new CyclicBarrierDemo(3000,cyclicBarrier);
Thread thread2 = new Thread(cyclicBarrierDemo3);
thread.start();
thread1.start();
thread2.start();
System.out.println("所有线程执行结束执行时间:"+(System.currentTimeMillis() -startTime));
}
@SneakyThrows
@Override
public void run() {
System.out.println("开始执行:「」"+Thread.currentThread().getName()+System.currentTimeMillis());
Thread.sleep(timeOut);
long watingTime = System.currentTimeMillis();
System.out.println("等待:「」"+Thread.currentThread().getName()+watingTime);
cyclicBarrier.await();
System.out.println("完成:「」"+Thread.currentThread().getName() +" time: "+ (System.currentTimeMillis()-watingTime));
}
}
执行结果
开始执行:「」Thread-01592752948830
开始执行:「」Thread-11592752948830
所有线程执行结束执行时间:2
开始执行:「」Thread-21592752948831
等待:「」Thread-01592752949833
等待:「」Thread-11592752950835
等待:「」Thread-21592752951836
最后执行的方法+
完成:「」Thread-2 time: 0
完成:「」Thread-0 time: 2003
完成:「」Thread-1 time: 1001
Disconnected from the target VM, address: '127.0.0.1:58105', transport: 'socket'
Process finished with exit code 0
- 我们细细的品一品:为什么线程2等待的时间最短呢? 因为他是做后一个执行完的,他不用等待别人而是执行快的在等待他。
Code analysis
- 代码中我们分别给了3个线程,每个线程分别让执行不同的时间,然后通过调用CyclicBarrier的await方法,进行栏栅,第一个执行完后第一个进到栏栅状态所以等待第二个到达的时候第一个线已经等待了大约1000ms了,但是 第三个在此刻执行了2000MS,还有1000ms没有执行,所以还需等待第三个线程池,所以这个过程,第一个线程等待后两个线程大概用了2000MS 第二个等待随后一个线程大概用了1000s,只有第三个线程没有等待时间,在线程状态切换和执行的时候浪费了1MS。
- 从上面我们也可以看到我们将一个RunAble初始化后,他会在最后一次线程等待结束后立马执行。并且是在线程本身的任务之前执行的。
- 通过上面的分析,我们也证明了CyclicBarrier的功能。
总结
- CyclicBarrierd可以让多个线程之间相互等待
- 也可以,设置一个当所有线程都达到栏栅时再执行一个线程。(上面的例子,当船上满人的时候,这个时候船就会开动,这个开动就是Runable要执行的任务)
- CyclicBarrierd的栏栅是可以循环使用的,所以也叫回环栏栅。
参考资料
- https://blog.csdn.net/qq_17305249/article/details/78081002 (底层分析)
- https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CyclicBarrier.html(基本使用)
- https://blog.csdn.net/HalfImmortal/article/details/106796659(重点推荐)
- 2.运行一个demo
- ROWNUMBER() OVER( PARTITION BY COL1 ORDER BY COL2)/ ROWNUMBER() OVER( PARTITION BY COL1 ORDER BY CO
- 干货 | 前端常用的通信技术
- TP-LINK WR941N路由器研究
- ORA-01113问题的简单分析(r6笔记第3天)
- Tensorflow 中 learning rate decay 的奇技淫巧
- hive数据:名词解释
- 巧妙使用exchange partition的一个案例(r6笔记第1天)
- r与rjava
- 使用expect运行动态脚本(r6笔记第19天)
- 数据库日志中一条"异常"信息所包含的细节(r6笔记第18天)
- linux下编辑VI窗口插入与编辑命令
- rman中三个不完全恢复场景(r6笔记第16天)
- 关于delete,drop,truncate的问题 (r6笔记第14天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android Studio通过Artifactory搭建本地仓库优化编译速度的方法
- Android实现向本地写入一个XML文件和解析XML文件
- Android自定义View实现带4圆角或者2圆角的效果
- Android 在 res/layout 文件夹 下创建一个 子文件夹实例
- Android开发实现TextView超链接5种方式源码实例
- Android根据包名停止其他应用程序的方法
- Android APP存活检测方式
- 利用Android两行代码真正杀死你的App
- android判断应用是否已经启动的实例
- 解决android studio引用远程仓库下载慢(JCenter下载慢)
- 在Android中查看当前Activity是否销毁的操作
- Android 7.0 运行时权限弹窗问题的解决
- Android加密之全盘加密详解
- Android 实现彻底退出自己APP 并杀掉所有相关的进程
- 使用Android开发接入第三方原生SDK实现微信登录