Java并发工具类之同步屏障CyclicBarrier

  CyclicBarrier的字面意思是可以循环使用的Barrier,它要做的事情是让一个线程到达一个Barrier的时候被阻塞,直到最后一个线程到达Barrier,屏障才会放开,所有被Barrier拦截的线程才会继续运行。

  CyclicBarrier的默认的构造器是CyclicBarrier(int parties),参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。示例代码如下:

  

public class CyclicBarrierTest {

    private static CyclicBarrier barrier = new CyclicBarrier(2);

    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {

        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.print("thread1");
            }

        }).start();

        barrier.await();

        System.out.println("mainThread");
    }
}

  因为子线程和主线程的调度由CPU决定,每个线程都有可能优先执行,因此会产生两种不同的结果,可能的结果如下:

  mainThread
  thread1

  如果把CyclicBarrier的Barrier的个数由2改为3,则主线程和子线程会永远等待,因为没有第三个线程执行await方法,即没有第三个线程到达屏障,因此之前到达屏障的两个线程都不会继续执行。

  CyclicBarrier还提供了一个高级的构造器,CyclicBarrier(int parties, Runnable barrierAction),用于在线程到达屏障后,优先执行barrierAction线程里面的逻辑。比如有如下的场景,在所有的线程都处理完成后,打印“All Done”,可以参考如下代码:

  

public class CyclicBarrierTest2 {

    private static CyclicBarrier barrier = new CyclicBarrier(2,new DoneThread());

    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {

        new Thread(new Runnable() {

            @Override
            public void run() {

                System.out.println("thread1");
                try {
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }

        }).start();

        System.out.println("mainThread");
        barrier.await();
    }

    static class DoneThread implements Runnable{

        @Override
        public void run() {
            System.out.println("All Done");
        }

    }
}

  输出结果如下:

mainThread
thread1
All Done

  因此CyclicBarrier常用于处理,多线程计算最后合并计算结果的场景。

CyclicBarrier和CountDownLatch的区别:

  1.CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset方法重置,因此CyclicBarrier可以处理线程计算出错时重复计算的场景。

  2.CyclicBarrier还提供了别的有用的方法,如getNumberWaiting可以获得等待的线程数,isBroken方法可以了解阻塞的线程是否被中断等。

posted @ 2017-11-18 11:07  木易森林  阅读(430)  评论(0编辑  收藏  举报