多線程之CountDownLatch和CyclicBarriar使用

  CountDownLatch和CyclicBarriar是java.util.concurrent包下面提供的多線程同步工具,二者有點類似,至關於計數器,可是用處仍是有區別的。java

  CountDownLatch:用於在完成一組正在其它線程中執行的操做以前,它容許一個或多個線程一直等待,await()表示等待,等到其它線程所有執行結束後(即經過countDown()方法來減數,計數爲0,即其它線程執行完畢)而後繼續執行,示例代碼:多線程

public static void main(String[] args) {
        //該計數器初始值1,用於主線程發送命令
        final CountDownLatch latch1 = new CountDownLatch(1);
        //該計數器初始值爲2,用於響應命令接受完成
        final CountDownLatch latch2 = new CountDownLatch(2);
        //建立一個大小爲2線程池
        ExecutorService executor = Executors.newCachedThreadPool(); 
        for (int i = 0; i < 2; i++) {
            executor.submit(new Runnable() {
                public void run() {
                    try {
                        System.out.println("線程" + Thread.currentThread().getName() + "正準備接受命令");
                        //等待主線程發送命令
                        latch1.await();
                        System.out.println("線程" + Thread.currentThread().getName() + "已接受命令");
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("線程" + Thread.currentThread().getName() + "迴應命令處理結果");
                        //命令接受完畢,返回給主線程,latch2減1。
                        latch2.countDown();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        try {
            Thread.sleep((long) (Math.random() * 10000));
            System.out.println("線程" + Thread.currentThread().getName() + "即將發佈命令");
            //發送命令,latch1計數減1
            latch1.countDown(); 
            System.out.println("線程" + Thread.currentThread().getName() + "已發送命令,正在等待響應");
            //命令發送後處於等待狀態,其它線程所有響應完成,也就是latch2.countDown(),再繼續執行
            latch2.await(); 
            System.out.println("線程" + Thread.currentThread().getName() + "已收到全部響應結果");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //關閉線程池
        executor.shutdown(); 
    }

  CyclicBarriar:用於多個線程在一個指定的公共屏障點(或者說集合點)相互等待,await()方法表明屏障點,每次調用await(),計數(建立CyclicBarriar對象時傳入int類型的參數,表示初始計數)減一,直到減到0後,表示全部線程都抵達,而後開始執行後面的任務,示例代碼:dom

public static void main(String[] args) throws Exception {
        //建立CyclicBarrier對象並設置2個公共屏障點
        final CyclicBarrier barrier = new CyclicBarrier(2);
        //建立大小爲2的線程池
        ExecutorService executor = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 2; i++) {
            executor.submit(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep((long)(Math.random()*10000));
                        System.out.println("線程" + Thread.currentThread().getName() + "即將到達集合地點1,當前已有"
                                + barrier.getNumberWaiting() + "個已經到達,正在等候");
                        //若是沒有達到公共屏障點,則該線程處於阻塞狀態,若是達到公共屏障點則全部處於等待的線程都繼續往下運行
                        barrier.await();
                        
                        System.out.println("線程" + Thread.currentThread().getName() + "經過集合地點1");
                        
                        Thread.sleep((long)(Math.random()*10000));
                        System.out.println("線程" + Thread.currentThread().getName() + "即將到達集合地點2,當前已有"
                                + barrier.getNumberWaiting() + "個已經到達,正在等候");
                        barrier.await();
                        
                        System.out.println("線程" + Thread.currentThread().getName() + "經過集合地點2");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        //關閉線程池
        executor.shutdown();
    }

  注意:觀察CyclicBarrier的使用能夠發現,它計數減至0後,計數器會被重置,能夠再次使用,可能這也是它被定義爲Cyclic(週期的、循環的)緣由,這個是和CountDownLatch區別的地方。工具

相關文章
相關標籤/搜索