JUC併發工具--CyclicBarrier的使用和原理解析

CyclicBarrier和CountDownLatch一樣是一種同步輔助工具

CyclicBarrier 它允許一組線程在一個共同的屏障點彼此等待,所有線程到達屏障點後再全部同時執行。固定數量的線程在程序中必須彼此等待的時候,CyclicBarrier非常有用

同CountDownLatch不同的是:

  1. CyclicBarrier的某個線程運行到某個點上之後,該線程即停止運行,直到所有的線程都到達了這個點,所有線程才重新運行;CountDownLatch則不是,某線程運行到某個點上之後,只是給某個數值-1而已,該線程繼續運行
  2. CyclicBarrier只能喚起一個任務,CountDownLatch可以喚起多個任務
  3. CyclicBarrier可重用,CountDownLatch不可重用,計數值爲0該CountDownLatch就不可再用了
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CyclicBarrier;


public class Person implements Runnable {
    private CyclicBarrier barrier;
    private String name;

    public Person(CyclicBarrier barrier, String name) {
        this.barrier = barrier;
        this.name = name;
    }

    @Override
    public void run() {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
            System.out.println(sdf.format(new Date()) + " " + name + "出發去飯店");
            System.out.println(sdf.format(new Date()) + " " + name + "到了飯店");

            barrier.await();

            System.out.println(sdf.format(new Date()) + " " + name + "開始喫飯");
            System.out.println(sdf.format(new Date()) + " " + name + "喫完了");
            // 重用CyclicBarrier
            barrier.await();

            System.out.println(sdf.format(new Date()) + " " + name + "離開餐廳");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

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

        CyclicBarrier barrier = new CyclicBarrier(3);

        List<Thread> threads = new ArrayList<>(3);
        threads.add(new Thread(new Person(barrier, "張三")));
        threads.add(new Thread(new Person(barrier, "李四")));
        threads.add(new Thread(new Person(barrier, "王五")));

        for (Thread thread : threads) {
            thread.start();
        }

        //等待所有線程跑完
        for (Thread thread : threads) {
            thread.join();
        }
    }
    
經過測試:當使用 CyclicBarrier 和 不使用 CyclicBarrier

使用 CyclicBarrier:
17:31:42.395 張三出發去飯店
17:31:42.395 李四出發去飯店
17:31:42.396 張三到了飯店
17:31:42.395 王五出發去飯店
17:31:42.396 李四到了飯店
17:31:42.396 王五到了飯店
17:31:42.397 王五開始喫飯
17:31:42.397 張三開始喫飯
17:31:42.397 李四開始喫飯
17:31:42.397 張三喫完了
17:31:42.397 王五喫完了
17:31:42.397 李四喫完了
17:31:42.397 張三離開餐廳
17:31:42.397 李四離開餐廳
17:31:42.397 王五離開餐廳

不使用 CyclicBarrier:
17:27:36.764 張三出發去飯店
17:27:36.767 張三到了飯店
17:27:36.768 張三開始喫飯
17:27:36.768 張三喫完了
17:27:36.768 張三離開餐廳
17:27:36.764 王五出發去飯店
17:27:36.764 李四出發去飯店
17:27:36.769 李四到了飯店
17:27:36.769 李四開始喫飯
17:27:36.769 李四喫完了
17:27:36.769 李四離開餐廳
17:27:36.769 王五到了飯店
17:27:36.770 王五開始喫飯
17:27:36.770 王五喫完了
17:27:36.770 王五離開餐廳

原理:

  1. 在CyclicBarrier的內部定義了一個ReentrantLock的對象,然後再利用這個ReentrantLock對象生成一個Condition的對象
  2. 每當一個線程調用CyclicBarrier的await方法時,首先把剩餘屏障的線程數減1
  3. 然後判斷剩餘屏障數是否爲0:如果不是,利用Condition的await方法阻塞當前線
  4. 如果是,首先利用Condition的signalAll方法喚醒所有線程
  5. 最後重新生成Generation對象以實現屏障的循環使用

參考:
https://zhuanlan.zhihu.com/p/140324377?from_voters_page=true

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