CountDownLatch(閉鎖) 與 CyclicBarrier(柵欄)

1. 閉鎖

閉鎖是 J.U.C包下的一個同步組件。

閉鎖,圖從上往下看,countDown方法計(jì)數(shù)器減1

作用:

被等待線程調(diào)用countdown方法計(jì)數(shù)器減1,減到0時等待線程(調(diào)用await方法的線程)被喚醒。

  • 閉鎖場景下,一個或者多個線程等待其他線程準(zhǔn)備好了才被喚醒。

一個閉鎖工作起來就像一道大門:直到閉鎖達(dá)到終點(diǎn)狀態(tài)之前,門一直是關(guān)閉的,沒有線程通過,在終點(diǎn)狀態(tài)到來的時候,門開了,允許所有線程都通過。一旦閉鎖到達(dá)了終點(diǎn)狀態(tài),他就不能夠在改變狀態(tài)了,所以它會永遠(yuǎn)保持敞開的狀態(tài)。

適用場景

1.確保一個計(jì)算不會執(zhí)行,直到它需要的資源被初始化。
2.確保一個服務(wù)不會開始,直到它依賴的服務(wù)都已經(jīng)開始。
3.等待直到活動的所有部分都為繼續(xù)處理做好準(zhǔn)備。比如王者榮耀需要等待所有玩家準(zhǔn)備才能開始。

代碼實(shí)例

public class CountDownLatchExample1 {

    private final static int threadCount = 200;

    public static void main(String[] args) throws Exception {

        ExecutorService exec = Executors.newCachedThreadPool();

        final CountDownLatch countDownLatch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            final int threadNum = i;
            exec.execute(() -> {
                try {
                    test(threadNum);
                } catch (Exception e) {
                    log.error("exception", e);
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        countDownLatch.await();
        log.info("finish");
        exec.shutdown();
    }

    private static void test(int threadNum) throws Exception {
        Thread.sleep(100);
        log.info("{}", threadNum);
        Thread.sleep(100);
    }
}

2. 柵欄

圖從下往上看,await方法計(jì)數(shù)器加1

CyclicBarrier 字面意思是回環(huán)柵欄,回環(huán)的意思是它能夠被重復(fù)利用,當(dāng)然前提是在所有線程釋放了以后。

作用

柵欄描述的是線程間的相互等待,相互等待的線程都準(zhǔn)備好就可以繼續(xù)下去了。而且柵欄的計(jì)數(shù)器可以重置,這樣意味著其中有線程準(zhǔn)備過程執(zhí)行失敗可以全部重新準(zhǔn)備。

比較

能否復(fù)用 場景
CountDownLatch 計(jì)數(shù)器不能重置 一個或者多個線程等待其他線程執(zhí)行完成
CyclicBarrier 計(jì)數(shù)器可以重置 一般用于一組線程互相等待至某個狀態(tài),然后這一組線程再同時執(zhí)行

代碼實(shí)例

public class CyclicBarrierExample1 {

    private static CyclicBarrier barrier = new CyclicBarrier(5);

    public static void main(String[] args) throws Exception {

        ExecutorService executor = Executors.newCachedThreadPool();
        // 十個線程
        for (int i = 0; i < 10; i++) {
            final int threadNum = i;
            Thread.sleep(1000);
            executor.execute(() -> {
                try {
                    race(Thread.currentThread().getName());
                } catch (Exception e) {
                    System.out.println("exception "+ e);
                }
            });
        }
        executor.shutdown();
    }

    private static void race(String threadNum) throws Exception {
        Thread.sleep(1000);
        System.out.printf("%s is ready \n", threadNum);
        barrier.await();
        System.out.printf("%s continue \n", threadNum);
    }
}

參考鏈接:
http://www.itdecent.cn/p/79f95bb81c67
http://www.itdecent.cn/p/5812bb54c44f

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容