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個操作完成。今后我們在編寫多線程程序時,可以使用這個構件來管理一組獨立線程的執行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM