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。

  • 相关阅读:
    LeetCode 1122. Relative Sort Array (数组的相对排序)
    LeetCode 46. Permutations (全排列)
    LeetCode 47. Permutations II (全排列 II)
    LeetCode 77. Combinations (组合)
    LeetCode 1005. Maximize Sum Of Array After K Negations (K 次取反后最大化的数组和)
    LeetCode 922. Sort Array By Parity II (按奇偶排序数组 II)
    LeetCode 1219. Path with Maximum Gold (黄金矿工)
    LeetCode 1029. Two City Scheduling (两地调度)
    LeetCode 392. Is Subsequence (判断子序列)
    写程序判断系统是大端序还是小端序
  • 原文地址:https://www.cnblogs.com/dengzy/p/5800683.html
Copyright © 2011-2022 走看看