Java多線程之CyclicBarrier

CyclicBarrier

一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時 CyclicBarrier 很有用。因爲該 barrier 在釋放等待線程後可以重用,所以稱它爲循環 的 barrier。CyclicBarrier 支持一個可選的 Runnable 命令,在一組線程中的最後一個線程到達之後(但在釋放所有線程之前),該命令只在每個屏障點運行一次。若在繼續所有參與線程之前更新共享狀態,此屏障操作很有用。

可能這裏大家會比較疑惑CountDownLatch和CyclicBarrier究竟有什麼區別??

兩者主要用於多線程的併發執行。當一個線程需要等待另外一個或多個線程的執行時,就可以考慮用它倆。
 
共同點:


  • 兩者的共同點是都具有await()方法,並且執行此方法會引起線程的阻塞,達到某種條件才能繼續執行(這種條件也是兩者的不同)。

  • 還有一個共同點是其構造方法都接受一個int類型的參數,這個值作爲計數用,達到該次數即釋放等待的線程。

不同點:


  • CountDownLatch是減計數方式,計數==0時釋放所有等待的線程;CyclicBarrier是加計數方式,計數達到構造方法中參數指定的值時釋放所有等待的線程。

  • CountDownLatch當計數到0時,計數無法被重置;CyclicBarrier計數達到指定值時,計數置爲0重新開始。

  • CountDownLatch每次調用countDown()方法計數減一,調用await()方法只進行阻塞,對計數沒任何影響;CyclicBarrier只有一個await()方法,調用await()方法計數加1,若加1後的值不等於構造方法的值,則線程阻塞。
   舉個很生動的例子(哈哈,自賣自誇):CountDownLatch 是計數器, 線程完成一個就記一個, 就像報數一樣, 只不過是遞減的. 而CyclicBarrier更像一個水閘, 線程執行就想水流, 在水閘處都會堵住, 等到水滿(線程到齊)了, 纔開始泄流.

package com.uppower.thread;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(5, new TotalTask());

        // 實際系統是查出所有省編碼code的列表,然後循環,每個code生成一個線程。
        new BillTask(barrier, "北京").start();
        new BillTask(barrier, "上海").start();
        new BillTask(barrier, "廣西").start();
        new BillTask(barrier, "四川").start();
        new BillTask(barrier, "黑龍江").start();

    }

    static class TotalTask implements Runnable {

        public void run() {
            System.out.println("=======================================");
            System.out.println("開始全國彙總");       
            try {
                //doTotalBill() 讀取內存中各省的數據彙總,過程略。
                Thread.sleep(3000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            System.out.println("全國彙總完畢");       
            System.out.println("=======================================");
        }
    }

    /**
     * 子任務:計費任務
     */
    static class BillTask extends Thread {

        private CyclicBarrier barrier;

        // 代碼,按省代碼分類,各省數據庫獨立。
        private String code;

        BillTask(CyclicBarrier barrier, String code) {
            this.barrier = barrier;
            this.code = code;
        }

        public void run() {
            System.out.println("開始計算--" + code + "省--數據!");
            
            try {
                //doBill()
                Thread.sleep(5000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            
            // 把bill方法結果存入內存,如ConcurrentHashMap,vector等,代碼略
            System.out.println(code + "省已經計算完成,並通知彙總Service!");
            try {
                // 通知barrier已經完成
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(" 全國彙總完畢了--" + code + "省又可以happy了!");
        }
    }
}

運行輸出結果:

開始計算--北京省--數據!
開始計算--廣西省--數據!
開始計算--四川省--數據!
開始計算--上海省--數據!
開始計算--黑龍江省--數據!
北京省已經計算完成,並通知彙總Service!
廣西省已經計算完成,並通知彙總Service!
黑龍江省已經計算完成,並通知彙總Service!
四川省已經計算完成,並通知彙總Service!
上海省已經計算完成,並通知彙總Service!
=======================================
開始全國彙總

全國彙總完畢
=======================================
 全國彙總完畢了--北京省又可以happy了!
 全國彙總完畢了--黑龍江省又可以happy了!
 全國彙總完畢了--廣西省又可以happy了!
 全國彙總完畢了--四川省又可以happy了!
 全國彙總完畢了--上海省又可以happy了!

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