溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中CyclicBarrier和CountDownLatch的用法和區別是什么

發布時間:2021-08-22 16:20:32 來源:億速云 閱讀:380 作者:chen 欄目:開發技術

這篇文章主要介紹“Java中CyclicBarrier和CountDownLatch的用法和區別是什么”,在日常操作中,相信很多人在Java中CyclicBarrier和CountDownLatch的用法和區別是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java中CyclicBarrier和CountDownLatch的用法和區別是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

目錄
  • 前言

  • CountDownLatch

    • 例子

  • CyclicBarrier

    • 構造函數

    • 例子

  • 兩者區別

    前言

    CyclicBarrier和CountDownLatch這兩個工具都是在java.util.concurrent包下,并且平時很多場景都會使用到。
    本文將會對兩者進行分析,記錄他們的用法和區別。

    CountDownLatch

    CountDownLatch是一個非常實用的多線程控制工具類,稱之為“倒計時器”,它允許一個或多個線程一直等待,直到其他線程的操作執行完后再執行。

    CountDownLatch是通過一個計數器來實現的,計數器的初始值為線程的數量。每當一個線程完成了自己的任務后,計數器的值就會減1。當計數器值到達0時,它表示所有的線程已經完成了任務,然后在閉鎖上等待的線程就可以恢復執行任務。

    Java中CyclicBarrier和CountDownLatch的用法和區別是什么

    特點

    只能一次性使用(不能reset);主線程阻塞;某個線程中斷將永遠到不了屏障點,所有線程都會一直等待。

    例子

     	//創建初始化3個線程的線程池
        private ExecutorService                    threadPool     = Executors.newFixedThreadPool(3);
        //保存每個學生的平均成績
        private ConcurrentHashMap<String, Integer> map            = new ConcurrentHashMap<>();
        private CountDownLatch                     countDownLatch = new CountDownLatch(3);
    
        private void count() {
            for (int i = 0; i < 3; i++) {
                threadPool.execute(() -> {
                    //計算每個學生的平均成績,代碼略()假設為60~100的隨機數
                    int score = (int) (Math.random() * 40 + 60);
                    try {
                        Thread.sleep(Math.round(Math.random() * 1000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    map.put(Thread.currentThread().getName(), score);
                    System.out.println(Thread.currentThread().getName() + "同學的平均成績為" + score);
                    countDownLatch.countDown();
                });
            }
            this.run();
            threadPool.shutdown();
        }
    
        @Override
        public void run() {
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int result = 0;
            Set<String> set = map.keySet();
            for (String s : set) {
                result += map.get(s);
            }
            System.out.println("三人平均成績為:" + (result / 3) + "分");
        }
    
        public static void main(String[] args) throws InterruptedException {
            long now = System.currentTimeMillis();
            CyclicBarrier1 cb = new CyclicBarrier1();
            cb.count();
            Thread.sleep(100);
            long end = System.currentTimeMillis();
            System.out.println(end - now);
        }

    最終輸出結果:

    Java中CyclicBarrier和CountDownLatch的用法和區別是什么

    其中1194ms證明了會阻塞主線程。

    CyclicBarrier

    CyclicBarrier 的字面意思是可循環使用(Cyclic)的屏障(Barrier)。它要做的事情是,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最后一個線程到達屏障時,屏障才會開門,所有被屏障攔截的線程才會繼續干活。

    這個屏障之所以用循環修飾,是因為在所有的線程釋放彼此之后,這個屏障是可以重新使用的(reset()方法重置屏障點),這一點與CountDownLatch不同。

    CyclicBarrier是一種同步機制允許一組線程相互等待,等到所有線程都到達一個屏障點才退出await方法,它沒有直接實現AQS而是借助ReentrantLock來實現的同步機制。它是可循環使用的,而CountDownLatch是一次性的,另外它體現的語義也跟CountDownLatch不同,CountDownLatch減少計數到達條件采用的是release方式,而CyclicBarrier走向屏障點(await)采用的是Acquire方式,Acquire是會阻塞的,這也實現了CyclicBarrier的另外一個特點,只要有一個線程中斷那么屏障點就被打破,所有線程都將被喚醒(CyclicBarrier自己負責這部分實現,不是由AQS調度的),這樣也避免了因為一個線程中斷引起永遠不能到達屏障點而導致其他線程一直等待。屏障點被打破的CyclicBarrier將不可再使用(會拋出BrokenBarrierException)除非執行reset操作。

    構造函數

    CyclicBarrier有兩個構造函數:

    CyclicBarrier(int parties)
    int類型的參數表示有幾個線程來參與這個屏障攔截,(拿上面的例子,即有幾個人跟團旅游);

    CyclicBarrier(int parties,Runnable barrierAction)
    當所有線程到達一個屏障點時,優先執行barrierAction這個線程。

    最重要的一個方法:
    await();每個線程調用await(),表示我已經到達屏障點,然后當前線程被阻塞。

    例子

    	//創建初始化3個線程的線程池
        private ExecutorService                    threadPool     = Executors.newFixedThreadPool(3);
        //創建3個CyclicBarrier對象,執行完后執行當前類的run方法
        private CyclicBarrier                      cb             = new CyclicBarrier(3, this);
        //保存每個學生的平均成績
        private ConcurrentHashMap<String, Integer> map            = new ConcurrentHashMap<>();
    
        private void count() {
            for (int i = 0; i < 3; i++) {
                threadPool.execute(() -> {
                    //計算每個學生的平均成績,代碼略()假設為60~100的隨機數
                    int score = (int) (Math.random() * 40 + 60);
                    try {
                        Thread.sleep(Math.round(Math.random() * 1000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    map.put(Thread.currentThread().getName(), score);
                    System.out.println(Thread.currentThread().getName() + "同學的平均成績為" + score);
                    try {
                        //執行完運行await(),等待所有學生平均成績都計算完畢
                        cb.await();
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                });
            }
            threadPool.shutdown();
        }
    
        @Override
        public void run() {
            int result = 0;
            Set<String> set = map.keySet();
            for (String s : set) {
                result += map.get(s);
            }
            System.out.println("三人平均成績為:" + (result / 3) + "分");
        }
    
        public static void main(String[] args) throws InterruptedException {
            long now = System.currentTimeMillis();
            CyclicBarrier1 cb = new CyclicBarrier1();
            cb.count();
            Thread.sleep(100);
            long end = System.currentTimeMillis();
            System.out.println(end - now);
        }

    最終輸出結果:

    Java中CyclicBarrier和CountDownLatch的用法和區別是什么

    顯然沒有阻塞主線程。

    兩者區別

    • CountDownLatch的計數器只能使用一次。而CyclicBarrier的計數器可以使用reset()

    • 方法重置。所以CyclicBarrier能處理更為復雜的業務場景,比如如果計算發生錯誤,可以重置計數器,并讓線程們重新執行一次。

    • CyclicBarrier還提供其他有用的方法,比如getNumberWaiting方法可以獲得CyclicBarrier阻塞的線程數量。isBroken方法用來知道阻塞的線程是否被中斷。比如以下代碼執行完之后會返回true。

    • CountDownLatch會阻塞主線程,CyclicBarrier不會阻塞主線程,只會阻塞子線程。

    • 某線程中斷CyclicBarrier會拋出異常,避免了所有線程無限等待。

    我們來從jdk作者設計的目的來看,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:一個或者多個線程,等待其他多個線程完成某件事情之后才能執行;
    CyclicBarrier:多個線程互相等待,直到到達同一個同步點,再繼續一起執行。
    對于CountDownLatch來說,重點是“一個線程(多個線程)等待”,而其他的N個線程在完成“某件事情”之后,可以終止,也可以等待。而對于CyclicBarrier,重點是多個線程,在任意一個線程沒有完成,所有的線程都必須等待。

    CountDownLatch是計數器,線程完成一個記錄一個,只不過計數不是遞增而是遞減,而CyclicBarrier更像是一個閥門,需要所有線程都到達,閥門才能打開,然后繼續執行。

    到此,關于“Java中CyclicBarrier和CountDownLatch的用法和區別是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女