CyclicBarrier的使用
最近一直整并发这块东西,顺便写点Java并发的例子,给大家做个分享,也强化下自己记忆,如果有什么错误或者不当的地方,欢迎大家斧正。
CyclicBarrier是一种多线程并发控制实用工具,和CountDownLatch非常类似,它也可以实现线程间的计数等待,但是它的功能比CountDownLatch更加复杂且强大。CyclicBarrier可以理解为循环栅栏,这个计数器可以反复使用。比如,假设我们将计数器设置为10,那么凑齐第一批10个线程后,计数器就会归零,然后接着凑齐下一批10个线程,这就是它的内在含义。
LOL和王者荣耀的玩家很多,许多人应该都有打大龙的经历,话说前期大家打算一起去偷大龙,由于前期大家都比较弱,需要五个人都齐了才能打大龙,这样程序该如何实现呢?本人很菜,开始我的代码是这么写的(哈哈大家不要纠结我的时间):
public class KillDragon {
/**
* 模拟打野去打大龙
*/
public static void dayePlayDragon(){
System.out.println("打野在去打大龙的路上,需要10s");
}
/**
* 模拟上单去打大龙
*/
public static void shangdanPlayDragon(){
System.out.println("上单在去打大龙的路上,需要10s");
}
/**
* 模拟中单去打大龙
*/
public static void zhongdanPlayDragon(){
System.out.println("中单在去打大龙的路上,需要10s");
}
/**
* 模拟ADC和辅助去打大龙
*/
public static void adcAndFuzhuPlayDragon(){
System.out.println("ADC和辅助在去打大龙的路上,需要10s");
}
/**
* 模拟大家一起去打大龙
*/
public static void killDragon()
{
System.out.println("打大龙...");
}
public static void main(String[] args)
{
dayePlayDragon();
shangdanPlayDragon();
zhongdanPlayDragon();
adcAndFuzhuPlayDragon();
killDragon();
}
结果如下:
打野在去打大龙的路上,需要10s
上单在去打大龙的路上,需要10s
中单在去打大龙的路上,需要10s
ADC和辅助在去打大龙的路上,需要10s
打大龙...
这完了,大家在路上的时间就花了40s了,显然是错误的。要是都这么干,对方把你塔都要偷光了。不行得改进下,怎么改呢,多线程并发执行,如是我改成了下面这样的,用volatile关键字。
private static volatile int i = 4;
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
while (i!=0){
}
while (i==0) {
killDragon();
i--;
long t = System.currentTimeMillis() - start;
System.out.println("总共耗时:"+t+"毫秒");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
dayePlayDragon();
try {
Thread.sleep(10000);
i--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
shangdanPlayDragon();
try {
Thread.sleep(10000);
i--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
zhongdanPlayDragon();
try {
Thread.sleep(10000);
i--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
adcAndFuzhuPlayDragon();
try {
Thread.sleep(10000);
i--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
结果如下:
打野在去打大龙的路上,需要10s
上单在去打大龙的路上,需要10s
中单在去打大龙的路上,需要10s
ADC和辅助在去打大龙的路上,需要10s
打大龙...
总共耗时:10005毫秒
结果似乎还不错,但是处理起来实在是有点麻烦,需要 while (i!=0)一直在那循环着。这时候学到了用 CyclicBarrier来处理,代码如下:
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(5);
new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
killDragon();
long t = System.currentTimeMillis() - start;
System.out.println("总共耗时:"+t+"毫秒");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
dayePlayDragon();
try {
Thread.sleep(10000);
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
shangdanPlayDragon();
try {
Thread.sleep(10000);
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
zhongdanPlayDragon();
try {
Thread.sleep(10000);
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
adcAndFuzhuPlayDragon();
try {
Thread.sleep(10000);
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
大家都没到达之前都等待,结果如下:
打野在去打大龙的路上,需要10s
上单在去打大龙的路上,需要10s
中单在去打大龙的路上,需要10s
ADC和辅助在去打大龙的路上,需要10s
打大龙...
总共耗时:10002毫秒
CyclicBarrier相当于线程的计数器:
CyclicBarrier初始化时规定一个数目,然后计算调用了CyclicBarrier.await()进入等待的线程数。当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续。
CyclicBarrier就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。
CyclicBarrier初始时还可带一个Runnable的参数, 此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。
当然这样使用CyclicBarrier和使用CountDownLatch是没什么区别的,正如前文所说的CyclicBarrier的功能更加的复杂且强大。给大家看一个《实战Java高并发程序设计》一书上的一个例子。
比如:司令下达命令,要求10个士兵去一起完成一项任务。这时,就会要求10个士兵先集合报道,接着,一起雄赳赳气昂昂地去执行任务。当10个士兵都执行完了任务,那么司机就可以对外宣称,任务完成。相比CountDownLatch,CyclicBarrier可以接受一个参数作为BarrierAction。所谓的BarrierAction就是当计数器一次计数完成后,系统会执行的动作。如下构造函数,其中,parties表示技术总数,也就是参与的线程总数。
public CyclicBarrier(int parties, Runnable barrierAction)
下面示例演示了上述任务场景
public class CyclicBarrierDemo {
public static class Soldier implements Runnable {
private String soldier;
private final CyclicBarrier cyclicBarrier;
public Soldier(CyclicBarrier cyclicBarrier, String soldier) {
this.soldier = soldier;
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
cyclicBarrier.await();
doWork();
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
void doWork() {
try {
Thread.sleep(Math.abs(new Random().nextInt() % 10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(soldier + ":任务完成");
}
}
public static class BarrierRun implements Runnable {
boolean flag;
int N;
public BarrierRun(boolean flag, int N) {
this.flag = flag;
this.N = N;
}
@Override
public void run() {
if (flag) {
System.out.println("司令:[士兵" + N + "个,任务完成!");
} else {
System.out.println("司令:[士兵" + N + "个,集合完毕!");
flag = true;
}
}
}
public static void main(String args[]) {
final int N = 10;
Thread[] allSoldier = new Thread[N];
boolean flag = false;
CyclicBarrier cyclicBarrier = new CyclicBarrier(N, new BarrierRun(flag, N));
System.out.println("集合队伍!");
for (int i = 0; i < N; i++) {
System.out.println("士兵" + i + "报道!");
allSoldier[i] = new Thread(new Soldier(cyclicBarrier, "士兵" + i));
allSoldier[i].start();
}
}
}
执行结果如下:
集合队伍!
士兵0报道!
士兵1报道!
士兵2报道!
士兵3报道!
士兵4报道!
士兵5报道!
士兵6报道!
士兵7报道!
士兵8报道!
士兵9报道!
司令:[士兵10个,集合完毕!
士兵0:任务完成
士兵2:任务完成
士兵9:任务完成
士兵3:任务完成
士兵7:任务完成
士兵8:任务完成
士兵1:任务完成
士兵4:任务完成
士兵5:任务完成
士兵6:任务完成
司令:[士兵10个,任务完成!
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 举例详解
有时候会有这样的需求,多个线程同时工作,然后其中几个可以随意并发执行,但有一个线程需要等其他线程工作结束后,才能开始.举个例子,开启多个线程分块下载一个大文件,每个线程只下载固定的一截,最后由另外一个 ...
随机推荐
- {vlFeat}{matlab}{VS2010}{编译配置}
运行程序需要vlfeat与mex等在matlab与vs2010中配置,碰到了不少困难,下面给出解决方案 1.下载vlfeat,但是vlfeat目录中并没有编译好的mex文件,需要在vs2010中编译 ...
- SEO SEM
SEO:搜索引擎优化SEM:搜索引擎营销 SEO排名机制:搜索引擎蜘蛛 权重 算法 排名规则 搜索引擎提交入口: 1.百度搜索网站登入口 2.Google网站登入口 3.360搜索引擎登入入口 4.搜 ...
- matplotlib ----- 同一线条的不同颜色
对同一线条的各个段或者特殊点, 用不同的颜色. 参考下面 http://stackoverflow.com/questions/30121773/python-is-it-possible-to-c ...
- MySQL Geometry扩展在地理位置计算中的效率优势
由于在Geometry中,有相关自带函数和SPATIAL INDEX的性能优化,可以让某些位置计算的效率提升.以下是几种计算方法的效果对比. 1. 数据准备 首先创建一个数据表,这是一个店铺数据表,结 ...
- session 与 cookie 区别
一.Session的概念 Session 是存放在服务器端的,类似于Session结构来存放用户数据,当浏览器 第一次发送请求时,服务器自动生成了一个Session和一个Session ID用来唯一标 ...
- Exception in thread "main" java.lang.UnsupportedClassVersionError: com/crack
执行一个jar文件的时候抛异常了 Exception in thread "main" java.lang.UnsupportedClassVersionError: com/cr ...
- Unit02: 参数值注入 、 基于注解的组件扫描
Unit02: 参数值注入 . 基于注解的组件扫描 (4)IOC (Inversion Of Controll 控制反转) 什么是IOC? 对象之间的依赖关系由容器来建立. 什么是DI? (Depen ...
- Renesas APIs ***
一个线程,强行结束另外一个线程,并将其挂起: static void SuspendTask(TX_THREAD *thread) { UINT status = ; UINT state; stat ...
- 1DAY 初识Python
一 本节目标 了解编程语言 了解python及与其他语言的优劣对比 安装python解释器及环境变量配置.运行python交互式环境 打印hello world程序 初识变量.用户输入,流程控制,wh ...
- 将xml转为array
/** * 将xml转为array * @param string $xml * @throws Exception */ public function FromXml($xml) { if (!$ ...