CountDownLatch与CyclicBarrier
来源:互联网 发布:svm算法推荐 编辑:程序博客网 时间:2024/04/30 08:07
CountDownLatch
直译过来就是倒计数(CountDown)门闩(Latch)。倒计数不用说,门闩的意思顾名思义就是阻止前进。在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程。当计数器count变为0时,所有线程不再等待,同时运行。
CountDownLatch的作用和 Thread.join()方法类似,可用于一组线程和另外一组线程的协作。例如,主线程在做一项工作之前需要一系列的准备工作,只有这些准备工作都完成,主线程才能继续它的工作。这些准备工作彼此独立,所以可以并发执行以提高速度。在这个场景下就可以使用 CountDownLatch 协调线程之间的调度了。
上面说的有点儿抽象,还是用实际例子说明吧。。。
下面模拟的是一个短跑比赛,共3名运动员,那么比赛要开始的话,就必须等到所有的运动员准备完毕。
下面看代码:
<span style="font-size:18px;">package test;import java.io.IOException;import java.util.Random;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CountDownLatch;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Test4 { public static void main(String[] args) throws IOException, InterruptedException { //如果将参数改为4,但是下面只加入了3个选手,这永远等待下去 CountDownLatch begin = new CountDownLatch(3); ExecutorService executor = Executors.newFixedThreadPool(3); executor.submit(new Thread(new Runner(begin, "1号选手"))); executor.submit(new Thread(new Runner(begin, "2号选手"))); executor.submit(new Thread(new Runner(begin, "3号选手"))); executor.shutdown(); } } class Runner implements Runnable { // 当begin为0时,运动员起跑 private CountDownLatch begin; private String name; public Runner(CountDownLatch begin, String name) { super(); this.begin = begin; this.name = name; } @Override public void run() { try { Thread.sleep(1000 * (new Random()).nextInt(8)); System.out.println(name + " 准备好了..."); //count减一,当count为0时,等待结束,所有运动员准备完毕,比赛开始 begin.countDown(); //等待所有运动员准备好 begin.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + " 起跑!"); try {Thread.sleep((long)(Math.random()*1000));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} System.out.println(name + " end!"); } } </span>
输出结果:
2号选手 准备好了...
1号选手 准备好了...
3号选手 准备好了...
3号选手 起跑!
2号选手 起跑!
1号选手 起跑!
3号选手 end!
1号选手 end!
2号选手 end!
当 begin.await()会阻塞线程,当 begin.countDown()被调用之后,计数器count(为什么是count?看源码)减一,当count为0时,所有线程停止等待。
说完了CountDownLatch,再来看看CyclicBarrier。。。。。。
CyclicBarrier
CyclicBarrier翻译过来叫循环障碍。它主要的方法就是一个:await()。await() 方法没被调用一次,计数便会减少1,并阻塞住当前线程。当计数减至0时,阻塞解除,所有在此 CyclicBarrier 上面阻塞的线程开始运行。在这之后,如果再次调用 await() 方法,计数就又会变成 N-1,新一轮重新开始,这便是 Cyclic 的含义所在。
CyclicBarrier的使用并不难,但需要主要它所相关的异常。除了常见的异常,CyclicBarrier.await() 方法会抛出一个独有的 BrokenBarrierException。这个异常发生在当某个线程在等待本 CyclicBarrier 时被中断或超时或被重置时,其它同样在这个CyclicBarrier 上等待的线程便会收到 BrokenBarrierException而停止等待。
还是上面的例子,下面我们用CyclicBarrier实现一下:
package test;import java.io.IOException;import java.util.Random;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Test3 { public static void main(String[] args) throws IOException, InterruptedException { //如果将参数改为4,但是下面只加入了3个选手,这永远等待下去 //Waits until all parties have invoked await on this barrier. CyclicBarrier barrier = new CyclicBarrier(3); ExecutorService executor = Executors.newFixedThreadPool(3); executor.submit(new Thread(new Runner(barrier, "1号选手"))); executor.submit(new Thread(new Runner(barrier, "2号选手"))); executor.submit(new Thread(new Runner(barrier, "3号选手"))); executor.shutdown(); } } class Runner implements Runnable { // 当barrier为0时,运动员起跑 private CyclicBarrier barrier; private String name; public Runner(CyclicBarrier barrier, String name) { super(); this.barrier = barrier; this.name = name; } @Override public void run() { try { Thread.sleep(1000 * (new Random()).nextInt(8)); System.out.println(name + " 准备好了..."); // barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。 barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println(name + " 起跑!"); try {Thread.sleep((long)(Math.random()*1000));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} System.out.println(name + " end!"); } }
输出结果:
1号选手 准备好了...
2号选手 准备好了...
3号选手 准备好了...
3号选手 起跑!
1号选手 起跑!
2号选手 起跑!
2号选手 end!
3号选手 end!
1号选手 end!
功能和结果并没有什么不同
CyclicBarrier和 CountDownLatch 在用法上的不同
CountDownLatch适用于一组线程和另一个主线程之间的工作协作。一个主线程等待一组工作线程的任务完毕才继续它的执行是使用 CountDownLatch的主要场景;CyclicBarrier 用于一组或几组线程,还是以刚才短跑比赛为例,刚才只是一组选手比赛,如果我们改成两组呢???这时有两组选手,第一组全部跑完,第二组才能开始。这时候使用CyclicBarrier实现就很容易,因为CyclicBarrier每次count归零以后都会重置,所以可以循环使用,而CountDownLatch却不具备这个功能。
下面看例子:
package test;import java.io.IOException;import java.util.Random;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Test5 { public static void main(String[] args) throws IOException, InterruptedException { //如果将参数改为4,但是下面只加入了3个选手,这永远等待下去 //Waits until all parties have invoked await on this barrier. CyclicBarrier barrier = new CyclicBarrier(3); ExecutorService executor = Executors.newFixedThreadPool(3); executor.submit(new Thread(new Runner(barrier, "第1组:1号选手"))); executor.submit(new Thread(new Runner(barrier, "第1组:2号选手"))); executor.submit(new Thread(new Runner(barrier, "第1组:3号选手"))); executor.submit(new Thread(new Runner(barrier, "第2组:1号选手"))); executor.submit(new Thread(new Runner(barrier, "第2组:2号选手"))); executor.submit(new Thread(new Runner(barrier, "第2组:3号选手"))); executor.shutdown(); } } class Runner implements Runnable { // 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point) private CyclicBarrier barrier; private String name; public Runner(CyclicBarrier barrier, String name) { super(); this.barrier = barrier; this.name = name; } @Override public void run() { try { Thread.sleep(1000 * (new Random()).nextInt(8)); System.out.println(name + " 准备好了..."); // barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。 barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println(name + " 起跑!"); try {Thread.sleep((long)(Math.random()*1000));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} System.out.println(name + " end!"); } }
输出结果:
第1组:3号选手 准备好了...
第1组:1号选手 准备好了...
第1组:2号选手 准备好了...
第1组:2号选手 起跑!
第1组:3号选手 起跑!
第1组:1号选手 起跑!
第1组:1号选手 end!
第1组:3号选手 end!
第1组:2号选手 end!
第2组:1号选手 准备好了...
第2组:2号选手 准备好了...
第2组:3号选手 准备好了...
第2组:3号选手 起跑!
第2组:2号选手 起跑!
第2组:1号选手 起跑!
第2组:3号选手 end!
第2组:2号选手 end!
第2组:1号选手 end!
这确实使我们想要的结果。
那么使用CyclicBarrier会产生什么样的结果呢???
试验一下:
import java.io.IOException;import java.util.Random;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CountDownLatch;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Test6 { public static void main(String[] args) throws IOException, InterruptedException { //如果将参数改为4,但是下面只加入了3个选手,这永远等待下去 CountDownLatch begin = new CountDownLatch(3); ExecutorService executor = Executors.newFixedThreadPool(3); executor.submit(new Thread(new Runner(begin, "第1棒:1号选手"))); executor.submit(new Thread(new Runner(begin, "第1棒:2号选手"))); executor.submit(new Thread(new Runner(begin, "第1棒:3号选手"))); executor.submit(new Thread(new Runner(begin, "第2棒:1号选手"))); executor.submit(new Thread(new Runner(begin, "第2棒:2号选手"))); executor.submit(new Thread(new Runner(begin, "第2棒:3号选手"))); executor.shutdown(); } } class Runner implements Runnable { // 当begin为0时,运动员起跑 private CountDownLatch begin; private String name; public Runner(CountDownLatch begin, String name) { super(); this.begin = begin; this.name = name; } @Override public void run() { try { Thread.sleep(1000 * (new Random()).nextInt(8)); System.out.println(name + " 准备好了..."); //count减一,当count为0时,等待结束,所有运动员准备完毕,比赛开始 begin.countDown(); //等待所有运动员准备好 begin.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + " 起跑!"); try {Thread.sleep((long)(Math.random()*1000));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} System.out.println(name + " end!"); } }
输出结果:
第1组:2号选手 准备好了...
第1组:1号选手 准备好了...
第1组:3号选手 准备好了...
第1组:3号选手 起跑!
第1组:2号选手 起跑!
第1组:1号选手 起跑!
第1组:1号选手 end!
第1组:3号选手 end!
第1组:2号选手 end!
第2组:3号选手 准备好了...
第2组:3号选手 起跑!
第2组:3号选手 end!
第2组:1号选手 准备好了...
第2组:1号选手 起跑!
第2组:1号选手 end!
第2组:2号选手 准备好了...
第2组:2号选手 起跑!
第2组:2号选手 end!
因为count归零后一直保持为0,不可复用,所以使用一个CountDownLatch无法实现上述功能。
有没有发现CyclicBarrier这个名字真是起绝了,一个cycle....一切尽在不言中.....
- CountDownLatch 与 CyclicBarrier应用
- CountDownLatch与CyclicBarrier
- CountDownLatch与CyclicBarrier详解
- CountDownLatch与CyclicBarrier
- CountDownLatch与CyclicBarrier
- CountDownLatch与CyclicBarrier区别
- CountDownLatch与CyclicBarrier
- CountDownLatch与CyclicBarrier
- CyclicBarrier与CountDownLatch区别
- CountDownLatch与CyclicBarrier
- 闭锁CountDownLatch与栅栏CyclicBarrier
- 闭锁CountDownLatch与栅栏CyclicBarrier
- CountDownLatch与CyclicBarrier的区别
- 闭锁CountDownLatch与栅栏CyclicBarrier
- CountDownLatch与CyclicBarrier的区别
- 【java多线程】CountDownLatch与CyclicBarrier
- 闭锁CountDownLatch与栅栏CyclicBarrier
- 闭锁CountDownLatch与栅栏CyclicBarrier
- SVN配置方法
- libevent库1.4升级到2.0时无法flush的解决办法(互相踢下线)
- 《从零开始学Swift》学习笔记(Day 56)—— Swift编码规范之命名规范
- Dll的注意问题
- C语言学习之关键字第二讲
- CountDownLatch与CyclicBarrier
- 在Android上实现多进程构架的浏览器(浏览器开发)的讨论
- Unity导入FBX汇总
- A+B Problem(V)(南阳oj844)
- C++随机数重复的问题
- 深入理解Java:注解(Annotation)--注解处理器
- 融云调用图片,通讯录和语音异常
- MySQL学习记录
- 浅析NGUITools.DestroyImmediate和NGUITools.Destroy的区别