zoukankan      html  css  js  c++  java
  • 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。

  • 相关阅读:
    【消息队列MQ】各类MQ比较
    MySql查询功能梳理
    头条日常实习生面经 2018.11.28
    排序算法 JavaScript
    浅谈二分查找 JavaScript
    LeetCode17.电话号码的字母组合 JavaScript
    LeetCode16.最接近的三数之和 JavaScript
    LeetCode15.三数之和 JavaScript
    LeetCode14.最长公共前缀 JavaScript
    LeetCode13.罗马数字转整数 JavaScript
  • 原文地址:https://www.cnblogs.com/dengzy/p/5800683.html
Copyright © 2011-2022 走看看