CyclicBarrier和CountDownLatch介紹

CyclicBarrier介紹 (一)
一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時 CyclicBarrier 很有用。因爲該 barrier 在釋放等待線程後可以重用,所以稱它爲循環 的 barrier。CyclicBarrier 支持一個可選的 Runnable 命令,在一組線程中的最後一個線程到達之後(但在釋放所有線程之前),該命令只在每個屏障點運行一次。若在繼續所有參與線程之前更新共享狀態,此屏障操作 很有用。 
 
CyclicBarrier (週期障礙)類可以幫助同步,它允許一組線程等待整個線程組到達公共屏障點。CyclicBarrier 是使用整型變量構造的,其確定組中的線程數。當一個線程到達屏障時(通過調用 CyclicBarrier.await()),它會被阻塞,直到所有線程都到達屏障,然後在該點允許所有線程繼續執行。與CountDownLatch不同的是,CyclicBarrier 所有公共線程都到達後,可以繼續執行下一個目標點,而CountDownLatch第一次到達指定點後,也就是記數器減制零,就無法再次執行下一目標工作。
 

應用場景
在某種需求中,比如一個大型的任務,常常需要分配好多子任務去執行,只有當所有子任務都執行完成時候,才能執行主任務,這時候,就可以選擇CyclicBarrier了。

實例分析
我們需要統計全國的業務數據。其中各省的數據庫是獨立的,也就是說按省分庫。並且統計的數據量很大,統計過程也比較慢。爲了提高性能,快速計算。我們採取併發的方式,多個線程同時計算各省數據,最後再彙總統計。在這裏CyclicBarrier就非常有用。看代碼:

主要類:

Java代碼 
  1. /**  
  2.  * 各省數據獨立,分庫存偖。爲了提高計算性能,統計時採用每個省開一個線程先計算單省結果,最後彙總。  
  3.  *   
  4.  * @author guangbo email:[email protected]  
  5.  *   
  6.  */  
  7. public class Total {   
  8.   
  9.     // private ConcurrentHashMap result = new ConcurrentHashMap();   
  10.   
  11.     public static void main(String[] args) {   
  12.         TotalService totalService = new TotalServiceImpl();   
  13.         CyclicBarrier barrier = new CyclicBarrier(5,   
  14.                 new TotalTask(totalService));   
  15.   
  16.         // 實際系統是查出所有省編碼code的列表,然後循環,每個code生成一個線程。   
  17.         new BillTask(new BillServiceImpl(), barrier, "北京").start();   
  18.         new BillTask(new BillServiceImpl(), barrier, "上海").start();   
  19.         new BillTask(new BillServiceImpl(), barrier, "廣西").start();   
  20.         new BillTask(new BillServiceImpl(), barrier, "四川").start();   
  21.         new BillTask(new BillServiceImpl(), barrier, "黑龍江").start();   
  22.   
  23.     }   
  24. }   
  25.   
  26. /**  
  27.  * 主任務:彙總任務  
  28.  */  
  29. class TotalTask implements Runnable {   
  30.     private TotalService totalService;   
  31.   
  32.     TotalTask(TotalService totalService) {   
  33.         this.totalService = totalService;   
  34.     }   
  35.   
  36.     public void run() {   
  37.         // 讀取內存中各省的數據彙總,過程略。   
  38.         totalService.count();   
  39.         System.out.println("=======================================");   
  40.         System.out.println("開始全國彙總");   
  41.     }   
  42. }   
  43.   
  44. /**  
  45.  * 子任務:計費任務  
  46.  */  
  47. class BillTask extends Thread {   
  48.     // 計費服務   
  49.     private BillService billService;   
  50.     private CyclicBarrier barrier;   
  51.     // 代碼,按省代碼分類,各省數據庫獨立。   
  52.     private String code;   
  53.   
  54.     BillTask(BillService billService, CyclicBarrier barrier, String code) {   
  55.         this.billService = billService;   
  56.         this.barrier = barrier;   
  57.         this.code = code;   
  58.     }   
  59.   
  60.     public void run() {   
  61.         System.out.println("開始計算--" + code + "省--數據!");   
  62.         billService.bill(code);   
  63.         // 把bill方法結果存入內存,如ConcurrentHashMap,vector等,代碼略   
  64.         System.out.println(code + "省已經計算完成,並通知彙總Service!");   
  65.         try {   
  66.             // 通知barrier已經完成   
  67.             barrier.await();   
  68.         } catch (InterruptedException e) {   
  69.             e.printStackTrace();   
  70.         } catch (BrokenBarrierException e) {   
  71.             e.printStackTrace();   
  72.         }   
  73.     }   
  74.   
  75. }  



結果:
開始計算--北京省--數據!
開始計算--上海省--數據!
北京省已經計算完成,並通知彙總Service!
開始計算--四川省--數據!
四川省已經計算完成,並通知彙總Service!
上海省已經計算完成,並通知彙總Service!
開始計算--廣西省--數據!
廣西省已經計算完成,並通知彙總Service!
開始計算--黑龍江省--數據!
黑龍江省已經計算完成,並通知彙總Service!
=======================================
開始全國彙總
CyclicBarrier介紹 (二)

張孝祥視頻學習筆記:

CyclicBarrier 表示大家彼此等待,大家集合好後纔開始出發,分散活動後又在i指定地點集合碰面,這就好比整個公司的人員利用週末時間集體郊遊一樣,先各自從家出發到公司集合後,再同時出發到公園遊玩,在指定地點集合後再同時開始就餐……

iimport java.util.concurrent.BrokenBarrierException;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierTest {
 public static void main(String [] args){
  ExecutorService service=Executors.newCachedThreadPool();
  final CyclicBarrier cb= new CyclicBarrier(3);  //三個線程同時到達
  for( int i=0;i<3;i++){        
   Runnable runnable=new Runnable(){
    public void run(){
     try {
      Thread.sleep((long)(Math.random()*10000));
      System. out.println("線程" +Thread.currentThread ().getName()+
        "即將到達集合地點1,當前已有" +(cb.getNumberWaiting()+1)+"個已到達"+
        (cb.getNumberWaiting()==2? "都到齊了,繼續走啊" :"正在等候" ));
      try {
       cb.await();
      } catch (BrokenBarrierException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
      Thread.sleep((long)(Math.random()*10000));
      System. out.println("線程" +Thread.currentThread ().getName()+
        "即將到達集合地點2,當前已有" +(cb.getNumberWaiting()+1)+"個已到達"+
        (cb.getNumberWaiting()==2? "都到齊了,繼續走啊" :"正在等候" ));
      try {
       cb.await();
      } catch (BrokenBarrierException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
      Thread.sleep((long)(Math.random()*10000));
      System.out.println("線程" +Thread.currentThread ().getName()+
        "即將到達集合地點3,當前已有" +(cb.getNumberWaiting()+1)+"個已到達"+
        (cb.getNumberWaiting()==2? "都到齊了,繼續走啊" :"正在等候" ));
      try {
       cb.await();
      } catch (BrokenBarrierException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
     } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
   };
   service.execute(runnable);
  }
  service.shutdown();
 }
}

運行結果:

線程pool-1-thread-3即將到達集合地點1,當前已有1個已到達正在等候
線程pool-1-thread-2即將到達集合地點1,當前已有2個已到達正在等候
線程pool-1-thread-1即將到達集合地點1,當前已有3個已到達都到齊了,繼續走啊
線程pool-1-thread-1即將到達集合地點2,當前已有1個已到達正在等候
線程pool-1-thread-2即將到達集合地點2,當前已有2個已到達正在等候
線程pool-1-thread-3即將到達集合地點2,當前已有3個已到達都到齊了,繼續走啊
線程pool-1-thread-2即將到達集合地點3,當前已有1個已到達正在等候
線程pool-1-thread-1即將到達集合地點3,當前已有2個已到達正在等候
線程pool-1-thread-3即將到達集合地點3,當前已有3個已到達都到齊了,繼續走啊

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