countDownLatch和CyclicBarrier应用区别
讨论 在同时开始 和 等待结束一起 两者的实现区别
countDown:
http://blog.csdn.net/gaolu/article/details/46224821
这个例子非常好
- class SubRunnable implements Runnable {
- private CountDownLatch begin, end;
- private List<Integer> sublist;
- public SubRunnable(List<Integer> sublist, CountDownLatch begin,CountDownLatch end) {
- this.sublist = sublist;
- this.begin = begin;
- this.end = end;
- }
- @Override
- public void run() {
- try {
- begin.await();
- if (sublist != null) {
- for (int i : sublist) {
- System.out.println("线程" + Thread.currentThread().getName() + ", i = " + i);
- }
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally{
- System.out.println(System.currentTimeMillis() + ",线程" + Thread.currentThread().getName() + ",开始执行!");
- end.countDown();
- }
- }
- }
- public class BatchWithCountDownLatch {
- private static final int MAX = 3;
- private static void list(List<Integer> list) {
- if(list == null){
- list = new ArrayList<Integer>();
- }
- for(int i = 0 ;i < 1000;i++){
- list.add(i);
- }
- }
- public static void main(String[] args) {
- List<Integer> list = new ArrayList<Integer>();
- list(list);
- //把list拆分成多个
- int mod = list.size() % MAX;
- int threadCount = mod == 0 ? list.size() / MAX : list.size() / MAX + 1;
- ExecutorService executors = Executors.newFixedThreadPool(threadCount);
- CountDownLatch begin = new CountDownLatch(1);
- CountDownLatch end = new CountDownLatch(threadCount);
- for(int i = 0; i< threadCount;i++){
- int subsize = (i + 1) * MAX;
- executors.execute(new SubRunnable(list.subList(i * MAX, subsize > list.size() ? list.size() : subsize),begin,end));
- }
- System.out.println("开始 !");
- begin.countDown();
- long startTime = System.currentTimeMillis();
- try {
- end.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- System.out.println("线程" + Thread.currentThread().getName() + "," + System.currentTimeMillis() + ", 所有线程已完成,开始进入下一步!");
- System.out.println("花费时间 -> " + (System.currentTimeMillis() - startTime) + " ms");
- }
- System.out.println("开始进入第二步操作! ");
- System.out.println("end! ");
- }
- }
两个countDownLatch,begin控制同时开始(尽管作者认为实践中没有必要),end控制等待一起返回
CyclicBarrier:
先看同时开始的例子:
https://www.jianshu.com/p/424374d71b67
想象一个场景,运动会男子100米决赛,8名选手。
Athlete.java :每个运动员都就位后才开始。
class Athlete implements Runnable { private CyclicBarrier cyclicBarrier; private String name; public Athlete(CyclicBarrier cyclicBarrier, String name) { this.cyclicBarrier = cyclicBarrier; this.name = name; } @Override public void run() { System.out.println(name + "就位"); try { cyclicBarrier.await(); Random random =new Random(); double time = random.nextDouble() + 9; System.out.println(name + ": "+ time); } catch (Exception e) { } } }run开始之初即await,等待其它线程一起开始
Race.java : 负责屏障的初始化。
class Race { private CyclicBarrier cyclicBarrier = new CyclicBarrier(8); public void start() { List<Athlete> athleteList = new ArrayList<>(); athleteList.add(new Athlete(cyclicBarrier,"博尔特")); athleteList.add(new Athlete(cyclicBarrier,"鲍威尔")); athleteList.add(new Athlete(cyclicBarrier,"盖伊")); athleteList.add(new Athlete(cyclicBarrier,"布雷克")); athleteList.add(new Athlete(cyclicBarrier,"加特林")); athleteList.add(new Athlete(cyclicBarrier,"苏炳添")); athleteList.add(new Athlete(cyclicBarrier,"路人甲")); athleteList.add(new Athlete(cyclicBarrier,"路人乙")); Executor executor = Executors.newFixedThreadPool(8); for (Athlete athlete : athleteList) { executor.execute(athlete); } } }
再来看结束后一起干的实例:
http://blog.csdn.net/gongpulin/article/details/51236398
- import java.util.concurrent.BrokenBarrierException;
- import java.util.concurrent.CyclicBarrier;
- public class CyclicBarrierTest {
- public static void main(String[] args) {
- //创建CyclicBarrier对象,
- //并设置执行完一组5个线程的并发任务后,再执行MainTask任务
- CyclicBarrier cb = new CyclicBarrier(5, new MainTask());
- new SubTask("A", cb).start();
- new SubTask("B", cb).start();
- new SubTask("C", cb).start();
- new SubTask("D", cb).start();
- new SubTask("E", cb).start();
- }
- }
- /**
- * 最后执行的任务
- */
- class MainTask implements Runnable {
- public void run() {
-
//根据jdkdoc里的描述,哪个线程最后运行完,就执行下面的代码。
- System.out.println("......执行最后的任务了......");
- }
- }
- /**
- * 一组并发任务
- */
- class SubTask extends Thread {
- private String name;
- private CyclicBarrier cb;
- SubTask(String name, CyclicBarrier cb) {
- this.name = name;
- this.cb = cb;
- }
- public void run() {
- System.out.println("[并发任务" + name + "] 开始执行");
- for (int i = 0; i < 999999; i++) ; //模拟耗时的任务
- System.out.println("[并发任务" + name + "] 开始执行完毕,通知障碍器");
- try {
- //每执行完一项任务就通知障碍器
- cb.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (BrokenBarrierException e) {
- e.printStackTrace();
- }
- }
- }
[并发任务A] 开始执行
[并发任务B] 开始执行
[并发任务B] 开始执行完毕,通知障碍器
[并发任务C] 开始执行
[并发任务C] 开始执行完毕,通知障碍器
[并发任务A] 开始执行完毕,通知障碍器
[并发任务D] 开始执行
[并发任务D] 开始执行完毕,通知障碍器
[并发任务E] 开始执行
[并发任务E] 开始执行完毕,通知障碍器
......执行最后的任务了......
可以看到await放在线程run的最后,起执行完了通知作用
小结:最主要的:
1.闭锁CountDownLatch.await做减计数,而栅栏CyclicBarrier.await则是加计数。
2.CountDownLatch是一次性的,CyclicBarrier可以重用,重用之前应当调用CyclicBarrier对象的reset方法