一、CyclicBarrier工具類介紹
在上一篇文中我們介紹到了CountDownLatch工具類,其實CyclicBarrier和CountDownLatch工具類實現的功能差不多。我們可以從字面上理解CyclicBarrier意思就是可以循環使用的屏障。該工具類可以做到讓一組線程到達一個屏障點的時候被阻塞,直到最后一個線程到達才開啟屏障,繼續往下執行。CyclicBarrier默認的構造方法是一個CyclicBarrier(int parties)。參數parties表示屏障需要攔截的線程數量。每個線程都會去調用await()方法通知道CyclicBarrier我已經到達屏障了。然后當前這個線程被阻塞,一直到所有的線程都到達屏障。另外CyclicBarrier還提供一個更高級的構造函數CyclicBarrier(int parties,Runnable barrier-Action),用於在線程到達屏障時,優先執行barrierAction中的業務代碼,方便處理更復雜的業務場景需求。
場景使用:Boss要開會,會議需要等到N個人到齊才能夠正常進行開展。這個場景中就適合使用CyclicBarrier工具類。
1 2 import java.io.IOException; 3 import java.util.concurrent.BrokenBarrierException; 4 import java.util.concurrent.CyclicBarrier; 5 import java.util.concurrent.ExecutorService; 6 import java.util.concurrent.Executors; 7 8 public class CyclicBarrierUserCase { 9 10 public static void main(String[] args) throws IOException, InterruptedException { 11 12 CyclicBarrier barrier = new CyclicBarrier(5,new Runnable() { 13 @Override 14 public void run() { 15 System.out.println(" 開會了,996工作要開始了!"); 16 } 17 }); 18 19 ExecutorService executor = Executors.newFixedThreadPool(5); 20 executor.submit(new Thread(new Worker(barrier, "項目經理"))); 21 executor.submit(new Thread(new Worker(barrier, "產品經理"))); 22 executor.submit(new Thread(new Worker(barrier, "程序員1號"))); 23 executor.submit(new Thread(new Worker(barrier, "程序員2號"))); 24 executor.submit(new Thread(new Worker(barrier, "程序員3號"))); 25 executor.shutdown(); 26 27 } 28 29 30 31 } 32 class Worker implements Runnable{ 33 // 一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點 (common barrier point) 34 private CyclicBarrier barrier; 35 private String name; 36 37 public Worker(CyclicBarrier barrier,String name){ 38 this.barrier = barrier; 39 this.name = name; 40 } 41 42 @Override 43 public void run() { 44 try{ 45 System.out.println(name + " 准備好了..."); 46 // barrier的await方法,在所有參與者都已經在此 barrier 上調用 await 方法之前,將一直等待。 47 barrier.await(); 48 }catch (InterruptedException e) { 49 e.printStackTrace(); 50 } catch (BrokenBarrierException e) { 51 e.printStackTrace(); 52 } 53 } 54 }
1 項目經理 准備好了... 2 程序員1號 准備好了... 3 程序員2號 准備好了... 4 程序員3號 准備好了... 5 產品經理 准備好了... 6 開會了,996工作要開始了!
其實await方法的處理邏輯除了一直等待到最后一個線程到達之外還有其他情況會終止線程的等待:
最后一個線程到達,即index == 0
超出了指定時間(超時等待)
其他的某個線程中斷當前線程
其他的某個線程中斷另一個等待的線程
其他的某個線程在等待barrier超時
其他的某個線程在此barrier調用reset()方法。reset()方法用於將屏障重置為初始狀態。
二、CyclicBarrier和CountDownLatch的比較
1. CountDownLatch計數器不可以復用,即計數器使用以后不能夠重置,但是CyclicBarrier可以調用reset()重置。當計算任務失敗的時候可以重新計算。
2. CyclicBarrier提供了更多的方法例如getNumberWaiting方法可以獲得Cyclic-Barrier 阻塞的線程數量。isBroken()方法用來了解阻塞的線程是否被中斷。
3. CountDownLatch計數器是通過調用countDown()方法進行減一計算,調用await()方法只進行阻塞,對計數沒任何影響。CyclicBarrier是通過調用await()方法進行加1運算。若加1后的值不等於構造方法的值,則線程阻塞。