Java并发编程之CyclicBarrier

CyclicBarrier

  1. 运行原理图

    图片

    假如有3个线程,内部运行时都使用了同一个CyclicBarrier,假如Thread1先到达屏障点,那么此时由于Thread2和Thread3还未到达,此时Thread1会等待;过了一会儿Thread2到达屏障点,此时Thread3还未到达,此时Thread2也会等待;最后,Thread3到达屏障点,发现Thread1和Thread2都到达了屏障点,此时Thread3会执行屏障动作(如果设置的话),然后唤醒Thread1和Thread2进入下一轮的执行。

  2. 实现原理:主要是用ReentrantLock来实现的,先到达屏障点的线程执行Condition.await方法,进行等待;最后到达屏障点的线程执行Condition.notifyAll方法唤醒所有的等待线程继续执行。

  3. 典型使用场景:让3个线程执行2轮然后退出执行的逻辑。

    public class CyclicBarrierTest {
    
        /**
         * 屏障个数
         */
        private int barrierCount = 3;
    
        /**
         * 共执行的轮数
         */
        private  int totalCount = 2;
    
        /**
         * 初始化一个屏障
         */
        private CyclicBarrier barrier = new CyclicBarrier(barrierCount,()->{
    
            if(totalCount-- == 1){
    
                doneFlag = true;
    
                System.out.println("执行完毕,退出屏障");
    
            }else {
    
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                System.out.println("第: " + (totalCount+1) + "轮执行结束");
            }
    
        });
    
        private volatile boolean doneFlag = false;
    
        class Task implements Runnable{
    
            @Override
            public void run() {
    
                while (!doneFlag){
    
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    try {
    
                        int order = barrier.await();
                        System.out.println(Thread.currentThread().getName()+"第 "+ (totalCount+1) +" 轮执行结束,执行次序:"+(barrierCount-order) );
    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
    
            }
        }
    
        public void test(){
    
    
            List<Thread> threads = new ArrayList<>();
    
            for(int i=0;i<barrierCount;i++){
    
                Thread thread = new Thread(new Task());
    
                thread.start();
    
                threads.add(thread);
    
            }
    
            //等待任务执行结束
            for(Thread thread : threads){
    
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
    
            System.out.println("所有任务执行完毕");
        }
    
        public static void main(String[] args){
    
            new CyclicBarrierTest().test();
        }
    
    
    
  4. 实际使用过程中要注意CyclicBarrier与CountDownLatch的区别,两者的主要区别是CyclicBarrier可以循环利用,而CountDownLatch不能够重复使用,

posted @ 2022-02-21 22:16  隐风  阅读(36)  评论(0)    收藏  举报