CountDownLatch升级版同步器Phaser

Phaser得功能远比CountDownLatch和CyclicBarrier更加强大,在特定场景中可以发挥更加重要得作用

用Phaser替代CountDownLatch

从JDK7开始,新增了一个同步工具类Phaser,其功能比CyclicBarrier和CountDownLatch更加强大。1.用Phaser替代CountDownLatch考虑讲CountDownLatch时的例子,1个主线程要等10个worker线程完成之后,才能做接下来的事情,也可以用Phaser来实现此功能。在CountDownLatch中,主要是2个函数:await()和countDown(),在Phaser中,与之相对应的函数是awaitAdance(int n)和arrive()。

    public static void main(String[] args) {
        Phaser phaser = new Phaser();
        phaser.awaitAdvance( 10 ); //等待10个同步点

        phaser.arrive(); //完成一个同步点执行一次此方法
    }

用Phaser替代CyclicBarrier

arriveAndAwaitAdance()就是arrive()与awaitAdvance(int)的组合,表示“我自己已到达这个同步点,同时要等待所有人都到达这个同步点,然后再一起前行”。

Phaser新特性特性

特性1:动态调整线程个数

CyclicBarrier 所要同步的线程个数是在构造函数中指定的,之后不能更改,而Phaser 可以在运行期间动态地调整要同步的线程个数。Phaser 提供了下面这些函数来增加、减少所要同步的线程个数。

    public static void main(String[] args) {
        Phaser phaser = new Phaser();
        phaser.register(); //注册一个同步点
        phaser.bulkRegister( 10 ); //注册10个同步点
        phaser.arriveAndDeregister(); //销毁一个同步点
    }

特性2:层次Phaser

在Phaser的内部结构中,每个Phaser记录了自己的父节点,但并没有记录自己的子节点列表。所以,每个Phaser 知道自己的父节点是谁,但父节点并不知道自己有多少个子节点,对父节点的操作,是通过子节点来实现的。

树状的Phaser怎么使用呢?考虑如下代码,会组成如图示的树状Phaser。

本来root有两个参与者,然后为其加入了两个子Phaser(c1,c2),每个子Phaser会算作1个参与者,root的参与者就变成2+2=4个。c1本来有3个参与者,为其加入了一个子Phaser c3,参与者数量变成3+1=4个。c3的参与者初始为0,后续可以通过调用register()函数加入。对于树状Phaser上的每个节点来说,可以当作一个独立的Phaser来看待,其运作机制和一个单独的Phaser是一样的。具体来讲:父Phaser并不用感知子Phaser的存在,当子Phaser中注册的参与者数量大于0时,会把自己向父节点注册;当子Phaser中注册的参与者数量等于0时,会自动向父节点解注册。父Phaser把子Phaser当作一个正常参与的线程就可以了。

state变量解析

大致了解了Phaser的用法和新特性之后,下面仔细剖析其实现原理。Phaser没有基于AQS来实现,但具备AQS的核心特性:state变量、CAS操作、阻塞队列。先从state变量说起。

这个64位的state变量被拆成4部分,如图所示为state变量各部分表示的意思。

最高位0表示未同步完成,1表示同步完成,初始最高位为0。Phaser提供了一系列的成员函数来从state中获取图4-9中的几个数字,如下所示。

猜你喜欢

转载自blog.csdn.net/wmq880204/article/details/114604891