countDownLatch和CyclicBarrier应用区别

讨论  在同时开始  和   等待结束一起   两者的实现区别


countDown:

http://blog.csdn.net/gaolu/article/details/46224821

这个例子非常好



[java]
 view plain copy
  1. class SubRunnable implements Runnable {  
  2.     private CountDownLatch begin, end;  
  3.     private List<Integer> sublist;  
  4.       
  5.     public SubRunnable(List<Integer> sublist, CountDownLatch begin,CountDownLatch end) {  
  6.         this.sublist = sublist;  
  7.           
  8.         this.begin = begin;  
  9.         this.end = end;  
  10.     }  
  11.       
  12.     @Override  
  13.     public void run() {  
  14.         try {  
  15.             begin.await();            
  16.               
  17.             if (sublist != null) {  
  18.                 for (int i : sublist) {  
  19.                     System.out.println("线程" + Thread.currentThread().getName() + ", i = " + i);  
  20.                 }  
  21.             }  
  22.         } catch (InterruptedException e) {  
  23.             e.printStackTrace();  
  24.         } finally{  
  25.             System.out.println(System.currentTimeMillis() + ",线程" + Thread.currentThread().getName() + ",开始执行!");  
  26.             end.countDown();  
  27.         }  
  28.     }  
  29. }  
  30.   
  31. public class BatchWithCountDownLatch {  
  32.     private static final int MAX = 3;  
  33.       
  34.     private static void list(List<Integer> list) {  
  35.         if(list == null){  
  36.             list = new ArrayList<Integer>();  
  37.         }  
  38.           
  39.         for(int i = 0 ;i < 1000;i++){  
  40.             list.add(i);  
  41.         }  
  42.     }  
  43.   
  44.     public static void main(String[] args) {  
  45.         List<Integer> list = new ArrayList<Integer>();  
  46.         list(list);  
  47.           
  48.         //把list拆分成多个  
  49.         int mod = list.size() % MAX;  
  50.         int threadCount = mod == 0 ? list.size() / MAX : list.size() / MAX + 1;  
  51.         ExecutorService executors = Executors.newFixedThreadPool(threadCount);  
  52.           
  53.         CountDownLatch begin = new CountDownLatch(1);   
  54.         CountDownLatch end = new CountDownLatch(threadCount);   
  55.                   
  56.         for(int i = 0; i< threadCount;i++){  
  57.             int subsize = (i + 1) * MAX;  
  58.             executors.execute(new SubRunnable(list.subList(i * MAX, subsize > list.size() ? list.size() : subsize),begin,end));  
  59.         }  
  60.           
  61.         System.out.println("开始 !");  
  62.         begin.countDown();  
  63.         long startTime = System.currentTimeMillis();  
  64.           
  65.         try {  
  66.             end.await();  
  67.         } catch (InterruptedException e) {  
  68.             e.printStackTrace();  
  69.         } finally {  
  70.             System.out.println("线程" + Thread.currentThread().getName() + "," + System.currentTimeMillis() + ", 所有线程已完成,开始进入下一步!");  
  71.             System.out.println("花费时间 -> " + (System.currentTimeMillis() - startTime) + " ms");  
  72.         }  
  73.           
  74.         System.out.println("开始进入第二步操作! ");        
  75.           
  76.         System.out.println("end! ");  
  77.     }  
  78. }  
这是根据jdk文档中的伪代码例程,编写的一个例子,我们完全可以将这个例程改为只使用一个CountDownLatch来实现之。经过测试,发现begin的引入对程序基本无用,当list是1000的数量级时,最先启动的线程仍然比最后启动的快几十毫秒左右;而不设置begin开始闭锁的程序,也是完全一样的情况。


两个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


[java]
 view plain copy
  1. import java.util.concurrent.BrokenBarrierException;     
  2. import java.util.concurrent.CyclicBarrier;      
  3. public class CyclicBarrierTest {     
  4.         public static void main(String[] args) {     
  5.                 //创建CyclicBarrier对象,    
  6.                 //并设置执行完一组5个线程的并发任务后,再执行MainTask任务    
  7.                 CyclicBarrier cb = new CyclicBarrier(5new MainTask());     
  8.                 new SubTask("A", cb).start();     
  9.                 new SubTask("B", cb).start();     
  10.                 new SubTask("C", cb).start();     
  11.                 new SubTask("D", cb).start();     
  12.                 new SubTask("E", cb).start();    
  13.         }     
  14. }     
  15.     
  16. /**   
  17. * 最后执行的任务  
  18. */     
  19. class MainTask implements Runnable {     
  20.         public void run() {     
  21. //根据jdkdoc里的描述,哪个线程最后运行完,就执行下面的代码。
  22.                 System.out.println("......执行最后的任务了......");     
  23.         }     
  24. }     
  25.     
  26. /**   
  27. * 一组并发任务   
  28. */     
  29. class SubTask extends Thread {     
  30.         private String name;     
  31.         private CyclicBarrier cb;     
  32.     
  33.         SubTask(String name, CyclicBarrier cb) {     
  34.                 this.name = name;     
  35.                 this.cb = cb;     
  36.         }     
  37.     
  38.         public void run() {     
  39.                 System.out.println("[并发任务" + name + "]  开始执行");     
  40.                 for (int i = 0; i < 999999; i++) ;    //模拟耗时的任务     
  41.                 System.out.println("[并发任务" + name + "]  开始执行完毕,通知障碍器");     
  42.                 try {     
  43.                         //每执行完一项任务就通知障碍器     
  44.                         cb.await();     
  45.                 } catch (InterruptedException e) {     
  46.                         e.printStackTrace();     
  47.                 } catch (BrokenBarrierException e) {     
  48.                         e.printStackTrace();     
  49.                 }     
  50.         }     
  51. }   
结果:

[并发任务A]  开始执行
[并发任务B]  开始执行
[并发任务B]  开始执行完毕,通知障碍器
[并发任务C]  开始执行
[并发任务C]  开始执行完毕,通知障碍器
[并发任务A]  开始执行完毕,通知障碍器
[并发任务D]  开始执行
[并发任务D]  开始执行完毕,通知障碍器
[并发任务E]  开始执行
[并发任务E]  开始执行完毕,通知障碍器
......执行最后的任务了......


可以看到await放在线程run的最后,起执行完了通知作用


小结:最主要的:

1.闭锁CountDownLatch.await做减计数,而栅栏CyclicBarrier.await则是加计数。
2.CountDownLatch是一次性的,CyclicBarrier可以重用,重用之前应当调用CyclicBarrier对象的reset方法


原文地址:https://www.cnblogs.com/silyvin/p/9106681.html