• thread_CyclicBarrier回环栅栏


    CyclicBarrier回环栅栏,字面意思是可循环使用(Cyclic)的屏障(Barrier)。通过它可以实现让一组线程等待至某个状态之后再全部同时执行。

    它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。

    叫做回环是因为当所有等待线程都被释放以后,
    可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。

      await()            在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
      int await(long timeout, TimeUnit unit)     在所有参与者都已经在此屏障上调用 await 方法之前,将一直等待。
      int getNumberWaiting() 返回当前在屏障处等待的参与者数目。
      int getParties()             返回要求启动此 barrier 的参与者数目。
      boolean isBroken()       查询此屏障是否处于损坏状态。
      void reset()                 将屏障重置为其初始状态。

    1.简单例子

        // 给一组线程到达一同步点,之前时被阻塞,直到最后一个线程到达障时,拦截的线程才会继续干活。
        @Test
        public void cyclicBarrier1Test() throws InterruptedException {
            // 参数表示屏障拦截的线程数量,
            CyclicBarrier c = new CyclicBarrier(2);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // 每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
                        c.await();
                    } catch (Exception e) {
                    }
                    System.out.println(1);
                }
            }).start();
            // 第二次到达,之前到达屏障的两个线程都不会继续执行。到达后任意个线程先执行,再执行下个
            try {
                c.await();
            } catch (Exception e) {
            }
            System.out.println(2);
        }
        返回
             1
             2
        @Test
        public void cyclicBarrier2Test() throws InterruptedException {
            // 在线程到达屏障时,优先执行 A 线程
            CyclicBarrier c = new CyclicBarrier(2, new A());
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        c.await();
                    } catch (Exception e) {
                    }
                    System.out.println(1);
                }
            }).start();
            try {
                c.await();
            } catch (Exception e) {
    
            }
            System.out.println(2);
        }
        class A implements Runnable {
            @Override
            public void run() {
                System.out.println(3);
            }
        }
    返回

           3
           1
           2

    2.处理复杂

    CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
      CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。
        /*
        @Test
        public void cyclicBarrier3Test() throws InterruptedException, BrokenBarrierException {
            CyclicBarrier c = new CyclicBarrier(2);
            Thread thread = new Thread(new Runnable() {
    
                @Override
                public void run() {
                    try {
                        c.await();
                    } catch (Exception e) {
                    }
                }
            });
            thread.start();
            thread.interrupt();
            try {
                c.await();
            } catch (Exception e) {
                System.out.println("isBroken " + c.isBroken());
            }
        }

    3. 让线程同时开始

        @Test
        public void cyclicBarrier4Test() throws IOException, InterruptedException {
            CyclicBarrier barrier = new CyclicBarrier(4);
            ExecutorService executor = Executors.newFixedThreadPool(3);
            executor.submit(new Thread(new Runner(barrier, "1号选手")));
            executor.submit(new Thread(new Runner(barrier, "2号选手")));
            executor.submit(new Thread(new Runner(barrier, "3号选手")));
    
            executor.shutdown();
            try {
                barrier.await();
                System.out.println("isBroken ");
    
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
    
    class Runner implements Runnable {
        // 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)
        private CyclicBarrier barrier;
    
        private String name;
    
        public Runner(CyclicBarrier barrier, String name) {
            super();
            this.barrier = barrier;
            this.name = name;
        }
    
        @Override
        public void run() {
            try {
                Thread.sleep(100 * (new Random()).nextInt(8));
                System.out.println(name + " 准备好了...");
                // barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(name + " 起跑!");
        }
    }

    4.CyclicBarrier和CountDownLatch的区别
       CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
       CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。

  • 相关阅读:
    .NETCORE微服务架构--网关篇(Ocelot)
    Hangfire实战--添加DashBoard登录权限
    IIS发布-HTTP谓词限制访问
    基于Dapper的泛型Repository
    .Net Framework JWT验证
    .Net Framework swagger 进阶----头部参数
    .Net Framework下安装api swagger
    ErrorSet
    201907总结
    博客美化
  • 原文地址:https://www.cnblogs.com/dengzy/p/5800683.html
Copyright © 2020-2023  润新知