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

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