最近一直整并发这块东西,顺便写点Java并发的例子,给你们作个分享,也强化下本身记忆,若是有什么错误或者不当的地方,欢迎你们斧正。多线程
CyclicBarrier是一种多线程并发控制实用工具,和CountDownLatch很是相似,它也能够实现线程间的计数等待,可是它的功能比CountDownLatch更加复杂且强大。CyclicBarrier能够理解为循环栅栏,这个计数器能够反复使用。好比,假设咱们将计数器设置为10,那么凑齐第一批10个线程后,计数器就会归零,而后接着凑齐下一批10个线程,这就是它的内在含义。并发
LOL和王者荣耀的玩家不少,许多人应该都有打大龙的经历,话说前期你们打算一块儿去偷大龙,因为前期你们都比较弱,须要五我的都齐了才能打大龙,这样程序该如何实现呢?本人很菜,开始个人代码是这么写的(哈哈你们不要纠结个人时间):dom
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(); }
结果以下:ide
打野在去打大龙的路上,须要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(); }
你们都没到达以前都等待,结果以下:this
打野在去打大龙的路上,须要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个,任务完成!