• 《java.util.concurrent 包源码阅读》27 Phaser 第一部分


    Phaser是JDK7新添加的线程同步辅助类,作用同CyclicBarrier,CountDownLatch类似,但是使用起来更加灵活:

    1. Parties是动态的。

    2. Phaser支持树状结构,即Phaser可以有一个父Phaser。

    Phaser的构造函数涉及到两个参数:父Phaser和初始的parties,因此提供了4个构造函数:

    public Phaser();
    public Phaser(int parties);
    
    public Phaser(Phaser parent);
    public Phaser(Phaser parent, int parties);

    因为Phaser的特色在在于动态的parties,因此首先来看动态更新parties是如何实现的。

    Phaser提供了两个方法:register和bulkRegister,前者会添加一个需要同步的线程,后者会添加parties个需要同步的线程。

        public int register() {
            return doRegister(1);
        }
    
        // 增加了参数的检查
        public int bulkRegister(int parties) {
            if (parties < 0)
                throw new IllegalArgumentException();
            if (parties == 0)
                return getPhase();
            return doRegister(parties);
        }

    两个方法都调用了doRegister方法,因此接下来就来看看doRegister方法

    在分析doRegister之前先来说说Phaser的成员变量:state,它存储了Phaser的状态信息:

    private volatile long state;

    1. state的最高位是一个标志位,1表示Phaser的线程同步已经结束,0表示线程同步正在进行

    2. state的低32位中,低16位表示没有到达的线程数量,高16位表示Parties值

    3. state的高32位除了最高位之外的其他31位表示的Phaser的phase,可以理解为第多少次同步(从0开始计算)。

    介绍完了state,来看方法doRegister

        private int doRegister(int registrations) {
            // 把registrations值同时加到parties值和还未达到的线程数量中去
            long adj = ((long)registrations << PARTIES_SHIFT) | registrations;
            final Phaser parent = this.parent;
            int phase;
            for (;;) {
                long s = state;
                int counts = (int)s;
                int parties = counts >>> PARTIES_SHIFT;
                int unarrived = counts & UNARRIVED_MASK;
                // 超过了允许的最大parties
                if (registrations > MAX_PARTIES - parties)
                    throw new IllegalStateException(badRegister(s));
                // 最高位为1,表示Phaser的线程同步已经结束
                else if ((phase = (int)(s >>> PHASE_SHIFT)) < 0)
                    break;
                // Phaser中的parties不是0
                else if (counts != EMPTY) {
                    // 如果当前Phaser没有父Phaser,或者如果有父Phaser,
                    // 刷新自己的state值,如果新后的state没有变化。
                    // 这里新子Phaser的原因在于,会出现父Phaser已经进入下一个phase
                    // 而子Phaser却没有及时进入下一个phase的延迟现象
                    if (parent == null || reconcileState() == s) {
                        // 如果所有线程都到达了,等待Phaser进入下一次同步开始
                        if (unarrived == 0)
                            root.internalAwaitAdvance(phase, null);
                        // 更新state成功,跳出循环完成注册
                        else if (UNSAFE.compareAndSwapLong(this, stateOffset,
                                                           s, s + adj))
                            break;
                    }
                }
                // 第一次注册,且不是子Phaser
                else if (parent == null) {
                    // 更新当前Phaser的state值成功则完成注册
                    long next = ((long)phase << PHASE_SHIFT) | adj;
                    if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next))
                        break;
                }
                // 第一次注册到子Phaser
                else {
                    // 锁定当前Phaser对象
                    synchronized (this) {
                        // 再次检查state值,确保没有被更新
                        if (state == s) {
                            // 注册到父Phaser中去
                            parent.doRegister(1);
                            do { // 获取当前phase值
                                phase = (int)(root.state >>> PHASE_SHIFT);
                            } while (!UNSAFE.compareAndSwapLong
                                     (this, stateOffset, state,
                                      ((long)phase << PHASE_SHIFT) | adj));// 更新当前Phaser的state值
                            break;
                        }
                    }
                }
            }
            return phase;
        }

    看完了注册,那么来看同步操作的arrive,这里也涉及到两个方法:arrive和arriveAndDeregister,前者会等待其他线程的到达,后者则会立刻返回:

        public int arrive() {
            return doArrive(false);
        }
    
        public int arriveAndDeregister() {
            return doArrive(true);
        }

    两个方法都调用了doArrive方法,区别在于参数一个是false,一个是true。那么来看doArrive:

        private int doArrive(boolean deregister) {
            // arrive需要把未到达的线程数减去1,
            // deregister为true,需要把parties值也减去1
            int adj = deregister ? ONE_ARRIVAL|ONE_PARTY : ONE_ARRIVAL;
            final Phaser root = this.root;
            for (;;) {
                // 如果是有父Phaser,首先刷新自己的state
                long s = (root == this) ? state : reconcileState();
                int phase = (int)(s >>> PHASE_SHIFT);
                int counts = (int)s;
                int unarrived = (counts & UNARRIVED_MASK) - 1;
                // 最高位为1,表示同步已经结束,返回phase值
                if (phase < 0)
                    return phase;
                // 如果parties为0或者在此次arrive之前所有线程到达
                else if (counts == EMPTY || unarrived < 0) {
                    // 对于非子Phaser来说,上述情况的arrive肯定是非法的
                    // 对于子Phaser首先刷新一下状态再做检查
                    if (root == this || reconcileState() == s)
                        throw new IllegalStateException(badArrive(s));
                }
                // 正常情况下,首先更新state
                else if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adj)) {
                    // 所有线程都已经到达
                    if (unarrived == 0) {
                        // 计算parties作为下一个phase的未到达的parties
                        long n = s & PARTIES_MASK;
                        int nextUnarrived = (int)n >>> PARTIES_SHIFT;
                        // 调用父Phaser的doArrive
                        if (root != this)
                            // 如果下一个phase的未到达的parties为0,则需要向
                            // 父Phaser取消注册
                            return parent.doArrive(nextUnarrived == 0);
                        // 正在进入下一个Phase,默认的实现是nextUnarrived为0
                        // 表示正在进入下一个Phase,因为下一个phase的parties
                        // 为0,需要等待parties不为0
                        if (onAdvance(phase, nextUnarrived))
                            // 正在等待下一个phase,设置状态为终止
                            n |= TERMINATION_BIT;
                        else if (nextUnarrived == 0)
                            // 下一个phase的parties为0,更新未到达的parties的值
                            n |= EMPTY;
                        else
                            // 更新下一个phase的未到达的parties的值
                            n |= nextUnarrived;
                        // phase值加1
                        n |= (long)((phase + 1) & MAX_PHASE) << PHASE_SHIFT;
    
                        // 更新state值
                        UNSAFE.compareAndSwapLong(this, stateOffset, s, n);
    
                        // 唤醒等待的线程
                        releaseWaiters(phase);
                    }
                    return phase;
                }
            }
        }

    关于arrive还有一个方法:arriveAndAwaitAdvance。这个方法会等到下一个phase开始再返回,相等于doArrive方法添加了awaitAdvance方法的功能。基本逻辑和上面说的doArrive方法类似:

        public int arriveAndAwaitAdvance() {
            final Phaser root = this.root;
            for (;;) {
                long s = (root == this) ? state : reconcileState();
                int phase = (int)(s >>> PHASE_SHIFT);
                int counts = (int)s;
                int unarrived = (counts & UNARRIVED_MASK) - 1;
                if (phase < 0)
                    return phase;
                else if (counts == EMPTY || unarrived < 0) {
                    // 对于非子Phaser来说,因为可以等待下一个phase,
                    // 所以不是非法arrive
                    if (reconcileState() == s)
                        throw new IllegalStateException(badArrive(s));
                }
                else if (UNSAFE.compareAndSwapLong(this, stateOffset, s,
                                                   s -= ONE_ARRIVAL)) {
                    // 还有其他线程没有达到,就会等待直到下一个phase开始
                    if (unarrived != 0)
                        return root.internalAwaitAdvance(phase, null);
                    if (root != this)
                        return parent.arriveAndAwaitAdvance();
                    long n = s & PARTIES_MASK;  // base of next state
                    int nextUnarrived = (int)n >>> PARTIES_SHIFT;
                    if (onAdvance(phase, nextUnarrived))
                        n |= TERMINATION_BIT;
                    else if (nextUnarrived == 0)
                        n |= EMPTY;
                    else
                        n |= nextUnarrived;
                    int nextPhase = (phase + 1) & MAX_PHASE;
                    n |= (long)nextPhase << PHASE_SHIFT;
                    if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))
                        return (int)(state >>> PHASE_SHIFT);
                    releaseWaiters(phase);
                    return nextPhase;
                }
            }
        }

    这一部分主要讲了Phaser的动态更新parties以及线程的arrive,下一部分将会分析线程等待的实现。

  • 相关阅读:
    【计算机视觉】深度学习视觉领域常用数据集汇总
    【计算机视觉】常用图像数据集
    【计算机视觉】ImageNet介绍
    【神经网络与深度学习】卷积与反卷积
    【视频开发】【计算机视觉】全景视频拼接关键技术
    【计算机视觉】分辨率与超分辨率图像重建
    【计算机视觉】【神经网络与深度学习】深度学习在图像超分辨率重建中的应用
    【VS开发】【C/C++开发】关于boost库的C++11导致的undefined符号问题
    【VS开发】【C/C++开发】vs2015编译boost 64位
    【视频开发】【计算机视觉】相机标定(Camera calibration)《二》
  • 原文地址:https://www.cnblogs.com/wanly3643/p/3985598.html
Copyright © 2020-2023  润新知