CycliBarriar和CountdownLatch有什麼區別

閱讀文本大概需要3分鐘。

      在Java中CycliBarriar和CountdownLatch有什麼區別?CyclicBarrier可以重複使用,而CountdownLatch不能重複使用。

       Java的concurrent包裏面的CountDownLatch其實可以把它看作一個計數器,只不過這個計數器的操作是原子操作,同時只能有一個線程去操作這個計數器,也就是同時只能有一個線程去減這個計數器裏面的值。可以向CountDownLatch對象設置一個初始的數字作爲計數值,任何調用這個對象上的await()方法都會阻塞,直到這個計數器的計數值被其他的線程減爲0爲止。所以在當前計數到達零之前,await 方法會一直受阻塞。之後,會釋放所有等待的線程,await的所有後續調用都將立即返回。這種現象只出現一次——計數無法被重置。如果需要重置計數,請考慮使用 CyclicBarrier。

       CountDownLatch一個非常典型的應用場景:有一個任務想要往下執行,但必須要等到其他的任務執行完畢後纔可以繼續往下執行。假如我們這個想要繼續往下執行的任務調用一個CountDownLatch對象的await()方法,其他的任務執行完自己的任務後調用同一個CountDownLatch對象上的countDown()方法,這個調用await()方法的任務將一直阻塞等待,直到這個CountDownLatch對象的計數值減到0爲止。

       CyclicBarrier一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時 CyclicBarrier 很有用。因爲該 barrier 在釋放等待線程後可以重用,所以稱它爲循環的 barrier。

總結如下:


0x01:CountDownLatch類只提供了一個構造器:

public CountDownLatch(int count) {  
          //參數count爲計數值
} 

然後下面這3個方法是CountDownLatch類中最重要的方法:

public void await() throws InterruptedException { 
          //調用await()方法的線程會被掛起,它會等待直到count值爲0才繼續執行
}   
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
          //和await()類似,只不過等待一定的時間後count值還沒變爲0的話就會繼續執行
}

public void countDown() {
          //將count值減1
}

CountDownLatch, 一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。

例子代碼:

import java.util.concurrent.CountDownLatch;

public class countDownlatchTest {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch countDownLatch = new CountDownLatch(5);
        for(int i=0;i<5;i++){
            new Thread(new readNum(i,countDownLatch)).start();
        }
        countDownLatch.await();
        System.out.println("線程執行結束。。。。");
    }

    static class readNum  implements Runnable{
        private int id;
        private CountDownLatch latch;
        public readNum(int id,CountDownLatch latch){
            this.id = id;
            this.latch = latch;
        }
        @Override
        public void run() {
            synchronized (this){
                System.out.println("id:"+id);
                latch.countDown();
                System.out.println("線程組任務"+id+"結束,其他任務繼續");
            }
        }
    }
}

輸出結果:

id:1
線程組任務1結束,其他任務繼續
id:0
線程組任務0結束,其他任務繼續
id:2
線程組任務2結束,其他任務繼續
id:3
線程組任務3結束,其他任務繼續
id:4
線程組任務4結束,其他任務繼續
線程執行結束。。。。

線程在countDown()之後,會繼續執行自己的任務,而CyclicBarrier會在所有線程任務結束之後,纔會進行後續任務。

0x02: CyclicBarrier用法

CyclicBarrier提供2個構造器

public CyclicBarrier(int parties, Runnable barrierAction) {
}

public CyclicBarrier(int parties) {
}

參數parties指讓多少個線程或者任務等待至barrier狀態;參數barrierAction爲當這些線程都達到barrier狀態時會執行的內容。

CyclicBarrier中最重要的方法就是await方法

public int await() throws InterruptedException, BrokenBarrierException { 
//掛起當前線程,直至所有線程都到達barrier狀態再同時執行後續任務;
}
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { 
//讓這些線程等待至一定的時間,如果還有線程沒有到達barrier狀態
//就直接讓到達barrier的線程執行後續任務
舉例說明
}

例子代碼:

import java.util.concurrent.CyclicBarrier;

public class cyclicBarrierTest {
    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                System.out.println("線程組執行結束");
            }
        });
        for (int i = 0; i < 5; i++) {
            new Thread(new readNum(i,cyclicBarrier)).start();
        }
        //CyclicBarrier 可以重複利用,
        // 這個是CountDownLatch做不到的
//        for (int i = 11; i < 16; i++) {
//            new Thread(new readNum(i,cyclicBarrier)).start();
//        }
    }
    static class readNum  implements Runnable{
        private int id;
        private CyclicBarrier cyc;
        public readNum(int id,CyclicBarrier cyc){
            this.id = id;
            this.cyc = cyc;
        }
        @Override
        public void run() {
            synchronized (this){
                System.out.println("id:"+id);
                try {
                    cyc.await();
                    System.out.println("線程組任務" + id + "結束,其他任務繼續");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

輸出結果:

id:1
id:2
id:4
id:0
id:3
線程組執行結束
線程組任務3結束,其他任務繼續
線程組任務1結束,其他任務繼續
線程組任務4結束,其他任務繼續
線程組任務0結束,其他任務繼續
線程組任務2結束,其他任務繼續

往期精彩

01 漫談發版哪些事,好課程推薦

02 Linux的常用最危險的命令

03 互聯網支付系統整體架構詳解

04 優秀的Java程序員必須瞭解的GC哪些

05 IT大企業有哪些病,別被這些病毀了自己?

關注我每天進步一點點

你點的在看,我都當成了喜歡

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章