JUC学习系列七(同步屏障 CyclicBarrier)

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。

public class Dragon {

    public void getBall(CyclicBarrier cb,int index){
        try {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"获得"+index+"星龙珠!");
            cb.await();
        } catch ( Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
       final CyclicBarrier cb=new CyclicBarrier(7, new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"集齐七颗龙珠召唤神龙!");
            }
        });
       final Dragon d=new Dragon();

        for (int i=1;i<8;i++){
           final int j=i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    d.getBall(cb,j);
                }
            }).start();
        }
        //检测重用性
        for (int i=1;i<8;i++){
            final int j=i;
            new Thread(new Runnable() {
                @Override
                public void run() {
//                   int b= 8/(j-5);
                    d.getBall(cb,j);
                }
            }).start();
        }
    }

}

《JUC学习系列七(同步屏障 CyclicBarrier)》

《JUC学习系列七(同步屏障 CyclicBarrier)》

这个工具类使用起来比较简单。API中的异常破坏模式,内存一致性还没弄懂。后面在做补充吧!

源码剖析

结构:

《JUC学习系列七(同步屏障 CyclicBarrier)》

我们在实例中new CyclicBarrier时,给它一个数目7和一个触发事件,在类中它们对应的就是parties和barrierCommand,如下:

《JUC学习系列七(同步屏障 CyclicBarrier)》

这个类就只有一个await()常用。我们看看它的底层到底是是怎样一个流程吧!

《JUC学习系列七(同步屏障 CyclicBarrier)》

 《JUC学习系列七(同步屏障 CyclicBarrier)》

 dowait()后面还有一个自旋方法,只要作用是当前线程阻塞时,检测它是否被打断等作用。感兴趣了可以自行阅读,比较简单。

 当前线程被打断时,或者中途抛出了异常在finally代码块里,调用的方法:

《JUC学习系列七(同步屏障 CyclicBarrier)》

初始化以便复用的方法:

《JUC学习系列七(同步屏障 CyclicBarrier)》

 以上就是其执行的原理。其中利用到了ReentrantLock。它自身也有一个count的int类型数值做计数器,跟AQS的思想很相近,当这个count减为0的时候,触发构造器里的线程任务类。每次调用await()方法,会使这个count计数器减一。中间也考虑到线程打断等情况,掺杂了相关的处理。源码还是很容易理解的。

    原文作者:JUC
    原文地址: https://blog.csdn.net/qq_38872310/article/details/81189183
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞