• 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方法


  • 相关阅读:
    jQuery -JQ方法大全
    Javascript模块化编程:模块的写法
    angular 路由的简单使用
    jQuery Validate验证框架
    网站出现403 Forbidden错误的原因和解决办法
    js下拉刷新
    bootstrap栅格系统的属性及使用
    AJAX 跨域请求
    用js实现分页效果
    用一个例子读懂 RequireJS
  • 原文地址:https://www.cnblogs.com/silyvin/p/9106681.html
Copyright © 2020-2023  润新知