zoukankan      html  css  js  c++  java
  • CountDownLatch和CyclicBarrier的区别

    在网上看到很多人对于CountDownLatch和CyclicBarrier的区别简单理解为CountDownLatch是一次性的,而 CyclicBarrier在调用reset之后还可以继续使用。那如果只是这么简单的话,我觉得CyclicBarrier简单命名为ResetableCountDownLatch好了,显然不是的。
    我的理解是,要从他们的设计目的去看这两个类。javadoc里面的描述是这样的。

    CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

    CyclicBarrier : A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.

    可能是我的英语不够好吧, 我感觉从这个javadoc里面要准确理解他们的差异还是不容易的。
    我的理解是

    CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。  CyclicBarrier        : N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。
    这样应该就清楚一点了,对于CountDownLatch来说,重点是那个“一个线程”, 是它在等待, 而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。而对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。

    CountDownLatch 是计数器, 线程完成一个就记一个, 就像 报数一样, 只不过是递减的.

    而CyclicBarrier更像一个水闸, 线程执行就想水流, 在水闸处都会堵住, 等到水满(线程到齐)了, 才开始泄流.

    CyclicBarrier

    假设有只有的一个场景:每个线程代表一个跑步运动员,当运动员都准备好后,才一起出发,只要有一个人没有准备好,大家都等待.

        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;  
          
        class Runner implements Runnable {  
          
            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 + " 准备OK.");  
                    barrier.await();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                } catch (BrokenBarrierException e) {  
                    e.printStackTrace();  
                }  
                System.out.println(name + " Go!!");  
            }  
        }  
          
        public class Race {  
          
            public static void main(String[] args) throws IOException, InterruptedException {  
                CyclicBarrier barrier = new CyclicBarrier(3);  
          
                ExecutorService executor = Executors.newFixedThreadPool(3);  
                executor.submit(new Thread(new Runner(barrier, "zhangsan")));  
                executor.submit(new Thread(new Runner(barrier, "lisi")));  
                executor.submit(new Thread(new Runner(barrier, "wangwu")));  
          
                executor.shutdown();  
            }  
          
        }  
     

    总结:CyclicBarrier就是一个栅栏,等待所有线程到达后再执行相关的操作。barrier 在释放等待线程后可以重用。

    CountDownLatch

        import java.util.concurrent.CountDownLatch;  
        /** 
         * 示例:CountDownLatch的使用举例 
         * Mail: ken@iamcoding.com 
         * @author janeky 
         */  
        public class TestCountDownLatch {  
            private static final int N = 10;  
          
            public static void main(String[] args) throws InterruptedException {  
                CountDownLatch doneSignal = new CountDownLatch(N);  
                CountDownLatch startSignal = new CountDownLatch(1);//开始执行信号  
          
                for (int i = 1; i <= N; i++) {  
                    new Thread(new Worker(i, doneSignal, startSignal)).start();//线程启动了  
                }  
                System.out.println("begin------------");  
                startSignal.countDown();//开始执行啦  
                doneSignal.await();//等待所有的线程执行完毕  
                System.out.println("Ok");  
          
            }  
          
            static class Worker implements Runnable {  
                private final CountDownLatch doneSignal;  
                private final CountDownLatch startSignal;  
                private int beginIndex;  
          
                Worker(int beginIndex, CountDownLatch doneSignal,  
                        CountDownLatch startSignal) {  
                    this.startSignal = startSignal;  
                    this.beginIndex = beginIndex;  
                    this.doneSignal = doneSignal;  
                }  
          
                public void run() {  
                    try {  
                        startSignal.await(); //等待开始执行信号的发布  
                        beginIndex = (beginIndex - 1) * 10 + 1;  
                        for (int i = beginIndex; i <= beginIndex + 10; i++) {  
                            System.out.println(i);  
                        }  
                    } catch (InterruptedException e) {  
                        e.printStackTrace();  
                    } finally {  
                        doneSignal.countDown();  
                    }  
                }  
            }  
        }  


    总结:CounDownLatch对于管理一组相关线程非常有用。上述示例代码中就形象地描述了两种使用情况。第一种是计算器为1,代表了两种状态,开 关。第二种是计数器为N,代表等待N个操作完成。今后我们在编写多线程程序时,可以使用这个构件来管理一组独立线程的执行。

  • 相关阅读:
    下载ts文件
    gradle plugins/repos/wrapper/tools 国内快速同步下载镜像
    两种方法教你绕过 TPM 2.0 安装 Win11,老电脑也能用 Win 11 了
    波兰极客用一张软盘运行Linux系统,用的还是最新内核
    ARM汇编编程基础
    String、String[]、ArrayList<String>之间的转换
    数据结构资源视频地址
    Zircon初体验-编译运行
    StarUML使用说明-指导手册
    华为RDPM项目管理方法
  • 原文地址:https://www.cnblogs.com/xiaorenwu702/p/3977833.html
Copyright © 2011-2022 走看看