CyclicBarrier 的使用

CyclicBarrier使用场景

用于协调多个线程同步执行操作的场合,所有线程等待完成,然后一起做事情( 相互之间都准备好,然后一起做事情 )

例如百米赛跑,必须等待所有运动员都准备好了,才能比赛。

运动员准备好,裁判也准备好,才能开始正式比赛。

例子

    CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
        new Thread(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("t1 在准备 ");
                cyclicBarrier.await();   // 等另外一个线程准备好 然后开始做事情
                System.out.println("t1 准备好了  ");
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }

        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(2000);
                System.out.println("t2 在准备  ");
                cyclicBarrier.await(); // 等另外一个线程准备好 然后开始做事情
                System.out.println("t2 准备好了  ");
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();
        
        System.out.println(" 裁判 在准备 ");
        try {
            cyclicBarrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println(" 裁判 准备好了 ");
        while (true){
            if (cyclicBarrier.getNumberWaiting()==0){
                System.out.println(" 时间到: 开始比赛");
                return;
            }
        }

 

 

关于CyclicBarrier的底层执行流程总结:

  • 1、初始化CyclicBarrier中的各种成员变量,包括parties、count以及Runnable(可选);

  • 2、当调用await()方法时,底层会先检查计数器是否已经归零,如果是的话,那么就首先执行可选的Runnable,接下来开始下一个generation;(注意:这里只是调用Runnable的run()方法,并不是调用start()方法开启另一个线程)

  • 3、在下一个分代中,将会重置count值为parties,并且创建新的Generation实例;

  • 4、同时会调用Condition的singalAll方法,唤醒所有在屏障前面等待的线程,让其开始继续执行;(注意:当有可选的Runnable时,是执行完run()方法中的汇总操作,其他线程才会继续执行)

  • 5、如果计数器没有归零,那么当前的调用线程将会通过Condition的await方法,在屏障前进行等待;

  • 6、以上所有执行流程均在lock锁的控制范围内,不会出现并发情况。

  • 7、在下一个分代时,该屏障又可以继续使用,例如计数器是3,线程1,线程2和线程3冲破了当前屏障后,下一个分代的屏障可以去给线程4,线程5和线程6使用,也可以又给线程1,线程2和线程3使用(自己总结的)

CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
            @Override
            public void run() {
                System.out.println("汇总 然后继续执行没有执行的部分");
            }
        });
CountDownLatch是基于AQS实现的;而CyclicBarrier是基于ReentrantLock重入锁实现的,当然ReentrantLock也是基于AQS实现的,非要说CyclicBarrier也是基于AQS实现的也不为过。
await()方法有两层含义:

1、先检查前面是否已经有count个线程了,如果没有线程则会进入等待状态
2、当检测到屏障已经有count个线程了,则所有线程会冲出屏障继续执行(如果有Runnable参数的构造方法先执行汇总方法)

posted @ 2023-02-22 17:44  xiaowang_lj  阅读(33)  评论(0编辑  收藏  举报