JUC同步锁原理源码解析五----Phaser

博客 分享
0 324
张三
张三 2023-06-19 22:10:43
悬赏:0 积分 收藏

JUC同步锁原理源码解析五----Phaser

JUC同步锁原理源码解析五----Phaser

Phaser

Phaser的来源

 A reusable synchronization barrier, similar in functionality to {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and {@link java.util.concurrent.CountDownLatch CountDownLatch} but supporting more flexible usage.

? JDK中对Phaser的定义时,一个可重用的同步栅栏。其作用相当于CyclicBarrier和CountDownLatch的结合体,但是支持更加灵活的使用

Phaser的底层实现

? Phaser的底层实现依旧依赖于CAS的自旋锁操作,通过cas保证原子性的操作

2.Phaser

基本使用

import java.util.List;
import java.util.concurrent.Phaser;

public class PhaserDemo {

    void runTasks(List<Runnable> tasks) {
        final Phaser phaser = new Phaser(1); // "1" to register self
        // create and start threads
        for (final Runnable task : tasks) {
            phaser.register();
            new Thread() {
                public void run() {
                    phaser.arriveAndAwaitAdvance(); // await all creation
                    task.run();
                }
            }.start();
        }
    }

    void startTasks(List<Runnable> tasks, int iterations) {
        Phaser phaser = new Phaser() {
            protected boolean onAdvance(int phase, int registeredParties) {
                return phase >= iterations - 1 || registeredParties == 0;
            }
        };
        phaser.register();
        for (Runnable task : tasks) {
            phaser.register();
            new Thread(() -> {
                do {
                    task.run();
                    phaser.arriveAndAwaitAdvance();
                } while (!phaser.isTerminated());
            }).start();
        }
        // allow threads to proceed; don't wait for them
        phaser.arriveAndDeregister();
    }
}

Phaser类

public class Phaser {
    private volatile long state;//采用long 64 位表示state变量。使用位操作来表示,cas单原子性变量保证多变量的原子性
    private static final int  MAX_PARTIES     = 0xffff;
    private static final int  MAX_PHASE       = Integer.MAX_VALUE;
    private static final int  PARTIES_SHIFT   = 16;
    private static final int  PHASE_SHIFT     = 32;
    private static final int  UNARRIVED_MASK  = 0xffff;      // to mask ints
    private static final long PARTIES_MASK    = 0xffff0000L; // to mask longs
    private static final long COUNTS_MASK     = 0xffffffffL;
    private static final long TERMINATION_BIT = 1L << 63;

    // some special values
    private static final int  ONE_ARRIVAL     = 1;
    private static final int  ONE_PARTY       = 1 << PARTIES_SHIFT;
    private static final int  ONE_DEREGISTER  = ONE_ARRIVAL|ONE_PARTY;
    private static final int  EMPTY           = 1;

    // The following unpacking methods are usually manually inlined

    private static int unarrivedOf(long s) {
        int counts = (int)s;
        return (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
    }

    private static int partiesOf(long s) {
        return (int)s >>> PARTIES_SHIFT;
    }

    private static int phaseOf(long s) {
        return (int)(s >>> PHASE_SHIFT);
    }

    private static int arrivedOf(long s) {
        int counts = (int)s;
        return (counts == EMPTY) ? 0 :
            (counts >>> PARTIES_SHIFT) - (counts & UNARRIVED_MASK);
    }

    /**
     * The parent of this phaser, or null if none
     */
    private final Phaser parent;

    /**
     * The root of phaser tree. Equals this if not in a tree.
     */
    private final Phaser root;

    /**
     * Heads of Treiber stacks for waiting threads. To eliminate
     * contention when releasing some threads while adding others, we
     * use two of them, alternating across even and odd phases.
     * Subphasers share queues with root to speed up releases.
     */
    private final AtomicReference<QNode> evenQ;
    private final AtomicReference<QNode> oddQ;

QNode类

static final class QNode implements ForkJoinPool.ManagedBlocker {
        final Phaser phaser;
        final int phase;
        final boolean interruptible;
        final boolean timed;
        boolean wasInterrupted;
        long nanos;
        final long deadline;
        volatile Thread thread; // nulled to cancel wait
        QNode next;

        QNode(Phaser phaser, int phase, boolean interruptible,
              boolean timed, long nanos) {
            this.phaser = phaser;
            this.phase = phase;
            this.interruptible = interruptible;
            this.nanos = nanos;
            this.timed = timed;
            this.deadline = timed ? System.nanoTime() + nanos : 0L;
            thread = Thread.currentThread();
        }

Phaser的构造器

public Phaser(int parties) {
    this(null, parties);
}

public Phaser(Phaser parent) {
    this(parent, 0);
}

//最终都是走这个构造器方法
public Phaser(Phaser parent, int parties) {
    if (parties >>> PARTIES_SHIFT != 0)//
        throw new IllegalArgumentException("Illegal number of parties");
    int phase = 0;
    this.parent = parent;
    if (parent != null) {//判断父阶段是否为空。如果有父阶段,子阶段的行为由父阶段控制,调用父阶段去处理
        final Phaser root = parent.root;//root为父阶段
        this.root = root;
        this.evenQ = root.evenQ;//使用父阶段的偶队列
        this.oddQ = root.oddQ;//使用父阶段的奇队列
        if (parties != 0)//如果父阶段不为空
            phase = parent.doRegister(1);//将当前阶段注册到父阶段中
    }
    else {//表示没有父阶段
        this.root = this;
        this.evenQ = new AtomicReference<QNode>();
        this.oddQ = new AtomicReference<QNode>();
    }
    this.state = (parties == 0) ? (long)EMPTY :
    ((long)phase << PHASE_SHIFT) | //64位中高32位表示阶段数,也即phase的数量
        ((long)parties << PARTIES_SHIFT) | //64位中低32位的高16位表示参与者的数量
        ((long)parties);//64位中低32位的低16位表示未完成的数量
}

register方法

public int register() {
    return doRegister(1);
}

private int doRegister(int registrations) {
    // adjustment to state
    long adjust = ((long)registrations << PARTIES_SHIFT) | registrations;//对当前state变量的参与数量和未完成数量都加 1
    final Phaser parent = this.parent;//如果有父阶段,获取父阶段
    int phase;
    for (;;) {
        long s = (parent == null) ? state : reconcileState();//拿到state的值
        int counts = (int)s;//将64位取低32位的值
        int parties = counts >>> PARTIES_SHIFT;//右移16位,取高16位的值,也即parties的数量
        int unarrived = counts & UNARRIVED_MASK;//获取低16位的数值,也即未到达的数量
        if (registrations > MAX_PARTIES - parties)//越界判断
            throw new IllegalStateException(badRegister(s));
        phase = (int)(s >>> PHASE_SHIFT);//获取阶段数
        if (phase < 0)//阶段数为0,表示已经超过阶段数了,不需要继续处理了
            break;
        if (counts != EMPTY) {                  // not 1st registration
            if (parent == null || reconcileState() == s) {
                if (unarrived == 0) // wait out advance 如果未完成数量等于0
                    root.internalAwaitAdvance(phase, null);//阻塞等待或者等到下一阶段推进
                else if (UNSAFE.compareAndSwapLong(this, stateOffset,//将当前需要参与的数量放到state变量中
                                                   s, s + adjust))
                    break;//退出循环
            }
        }
        else if (parent == null) {//没有父阶段或自己就是父阶段
            long next = ((long)phase << PHASE_SHIFT) | adjust; //阶段数量增加
            if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next))//cas尝试将阶段数量增加,成功就腿很粗
                break;
        }
        else {
            synchronized (this) {   //走到这里表示,自身属于子阶段,需要接受父阶段的调度
                if (state == s) {   //重新检测state变量是否改变
                    phase = parent.doRegister(1);//向父阶段注册
                    if (phase < 0)//阶段数已经超过了最大阶段数
                        break;
                   //while循环,设置state的中phase阶段数直至成功
                    while (!UNSAFE.compareAndSwapLong
                           (this, stateOffset, s,
                            ((long)phase << PHASE_SHIFT) | adjust)) {
                        s = state;
                        phase = (int)(root.state >>> PHASE_SHIFT);
                        // assert (int)s == EMPTY;
                    }
                    break;
                }
            }
        }
    }
    return phase;
}

reconcileState方法:

//只要使用在有父子阶段的存在的情况下
private long reconcileState() {
    final Phaser root = this.root;//获取到当前阶段
    long s = state;//取得当前state
    if (root != this) {//如果root不是当前阶段
        int phase, p;
        // CAS to root phase with current parties, tripping unarrived
        while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=  //phase等于root的阶段数
               (int)(s >>> PHASE_SHIFT) &&//root的阶段数不等于当前阶段state变量的阶段数
               !UNSAFE.compareAndSwapLong//
               (this, stateOffset, s,
                s = (((long)phase << PHASE_SHIFT) |  //root的阶段数
                     ((phase < 0) ? (s & COUNTS_MASK) : //如果阶段数已经超了,直接取低32位
                      (((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY : //获取到s对应的parties数量,复制给p
                       ((s & PARTIES_MASK) | p))))))
            s = state;
    }
    return s;
}

arriveAndAwaitAdvance方法

public int arriveAndAwaitAdvance() {
    // Specialization of doArrive+awaitAdvance eliminating some reads/paths
    final Phaser root = this.root;//获取当前阶段
    for (;;) {
        long s = (root == this) ? state : reconcileState();//获取到state的状态,如果有父阶段调用reconcileState
        int phase = (int)(s >>> PHASE_SHIFT);//等到当前阶段数
        if (phase < 0)//阶段数超了,直接返回
            return phase;
        int counts = (int)s;//获取state的低32位
        int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);//获取到未到达的参与者数量
        if (unarrived <= 0)//未到达的参与者数量越界检查
            throw new IllegalStateException(badArrive(s));
        if (UNSAFE.compareAndSwapLong(this, stateOffset, s,
                                      s -= ONE_ARRIVAL)) {//cas将未到达的数量减1
            if (unarrived > 1)//如果未到达的数量大于1
                return root.internalAwaitAdvance(phase, null);//调用父阶段控制其去睡眠等待
            if (root != this)//如果this不是父阶段
                return parent.arriveAndAwaitAdvance();//由父类处理,将到达线程数减1或滚动到下一阶段
            long n = s & PARTIES_MASK;  // base of next state//获得参与者parties数量
            int nextUnarrived = (int)n >>> PARTIES_SHIFT;//获得下一个阶段参与者的数量
            if (onAdvance(phase, nextUnarrived))//调用onAdvance会掉方法
                n |= TERMINATION_BIT;//TERMINATION_BIT:1<<63,标识阶段数结束
            else if (nextUnarrived == 0)//如果下一个阶段参与者为0
                n |= EMPTY;//异或上EMPTY
            else
                n |= nextUnarrived;//否则将低32位的低16位置为下一阶段参与者的数量,表示未完成的数量等于下一个阶段参与者的数量
            int nextPhase = (phase + 1) & MAX_PHASE;//获得下一个阶段的phase的数量
            n |= (long)nextPhase << PHASE_SHIFT;//n异或上下一阶段phase的数量组合成state比那辆
            if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))//cas设置state变量。当前线程如果设置state变量失败,是否可以允许爆炸唤醒,不直接退出?
                return (int)(state >>> PHASE_SHIFT); // cas失败,返回state中的阶段数
            releaseWaiters(phase);//释放等待线程
            return nextPhase;
        }
    }
}

internalAwaitAdvance方法

private int internalAwaitAdvance(int phase, QNode node) {
    // assert root == this;
    releaseWaiters(phase-1);          // ensure old queue clean  将上一个阶段等待线程唤醒,将队列清空
    boolean queued = false;           // true when node is enqueued
    int lastUnarrived = 0;            // to increase spins upon change
    int spins = SPINS_PER_ARRIVAL;//SPINS_PER_ARRIVAL = (NCPU < 2) ? 1 : 1 << 8,单核CPU没有自旋的必要,浪费时间
    long s;
    int p;
    while ((p = (int)((s = state) >>> PHASE_SHIFT)) == phase) {//判断当前阶段数是否等于phase
        if (node == null) {           // spinning in noninterruptible mode
            int unarrived = (int)s & UNARRIVED_MASK;//获取未到达的参与者数量
            if (unarrived != lastUnarrived &&//未到达的参与者数量不等于lastUnarrived
                (lastUnarrived = unarrived) < NCPU)//lastUnarrived 赋值lastUnarrived。小于CPU的核心数,证明任务很快可以调度,值得等待。但是考虑业务线程,实际中如果CPU的核心数没有大于2,其实没有自旋的必要。
                spins += SPINS_PER_ARRIVAL;//增加自旋次数
            boolean interrupted = Thread.interrupted();//判断中断标志位
            if (interrupted || --spins < 0) { // need node to record intr //如果中断了,或者自旋次数小于0
                node = new QNode(this, phase, false, false, 0L);
                node.wasInterrupted = interrupted;//将中断标识赋值
            }
        }
        else if (node.isReleasable()) // done or aborted 判断是否已经完成,或者说中断等方式释放
            break;
        else if (!queued) {           // push onto queue 不在队列中
            AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ; //根据phase的奇偶性,选择队列
            QNode q = node.next = head.get();//头插法
            if ((q == null || q.phase == phase) &&
                (int)(state >>> PHASE_SHIFT) == phase) // avoid stale enq
                queued = head.compareAndSet(q, node); 
        }
        else {
            try {
                ForkJoinPool.managedBlock(node);//由于兼容forkJoin线程池,所以这里提供模板。这里进行阻塞等待
            } catch (InterruptedException ie) {
                node.wasInterrupted = true;
            }
        }
    }

    if (node != null) {//进入这里表示,当前阶段不一致
        if (node.thread != null)
            node.thread = null;       // avoid need for unpark() //将thread置为空
        if (node.wasInterrupted && !node.interruptible) //节点被中断,并且节点不可中断
            Thread.currentThread().interrupt();//重置中断标志位
        if (p == phase && (p = (int)(state >>> PHASE_SHIFT)) == phase)//当前阶段数量一致,也即属于同一阶段
            return abortWait(phase); // possibly clean up on abort 
    }
    releaseWaiters(phase);//唤醒等待的线程
    return p;
}

releaseWaiters方法

private void releaseWaiters(int phase) {
    QNode q;   // first element of queue
    Thread t;  // its thread
    AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;//根据阶段数判断是奇数队列还是偶数队列
    while ((q = head.get()) != null &&//获取到头结点,如果头结点补位空
           q.phase != (int)(root.state >>> PHASE_SHIFT)) {//并且当前阶段数已经滚动到下一个阶段
        if (head.compareAndSet(q, q.next) &&//cas替换头结点
            (t = q.thread) != null) {//如果旧的头结点不为空
            q.thread = null;//将节点q的线程置为空
            LockSupport.unpark(t);//唤醒节点q的线程
        }
    }
}

arriveAndDeregister方法

public int arriveAndDeregister() {
    return doArrive(ONE_DEREGISTER);//ONE_DEREGISTER  = ONE_ARRIVAL|ONE_PARTY;
}

doArrive方法

private int doArrive(int adjust) {
    final Phaser root = this.root;//获取当前阶段
    for (;;) {
        long s = (root == this) ? state : reconcileState();//如果有父阶段获取父阶段的state,没有取当前阶段的state
        int phase = (int)(s >>> PHASE_SHIFT);//获取阶段数
        if (phase < 0)//如果阶段数已经小于0,表示已经结束,直接返回
            return phase;
        int counts = (int)s;//获取state的低32位,业绩参与者和未完成的参与者
        int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);//获取未到达的参与者数量EMPTY是特殊值,表示没有未到达的参与者
        if (unarrived <= 0)//如果未到达的参与者小于0,非法直接抛出异常
            throw new IllegalStateException(badArrive(s));
        if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adjust)) {//直接cas自旋,更新state变量
            if (unarrived == 1) {//如果当前线程是最后一个未完成的参与者,需要做收尾工作
                long n = s & PARTIES_MASK;  // base of next state 获取参与者的数量
                int nextUnarrived = (int)n >>> PARTIES_SHIFT;//设置未到达的参与者数量为下一个阶段的参与者数量
                if (root == this) {//如果root是当前阶段
                    if (onAdvance(phase, nextUnarrived))//回调钩子函数
                        n |= TERMINATION_BIT;//置为TERMINATION状态,TERMINATION_BIT = 1L << 63;最高位符号位表示终止标志位
                    else if (nextUnarrived == 0)//如果下一个阶段没有参与者
                        n |= EMPTY;//直接或上一个EMPTY
                    else
                        n |= nextUnarrived;//否则直接或上下一个阶段的未达到的参与者数量
                    int nextPhase = (phase + 1) & MAX_PHASE;//阶段数加1
                    n |= (long)nextPhase << PHASE_SHIFT;//将阶段数组合到变量n中,
                    UNSAFE.compareAndSwapLong(this, stateOffset, s, n);//cas自旋将state置为n,表示滚动到下一个阶段
                    releaseWaiters(phase);//释放所有等待的节点
                }
                else if (nextUnarrived == 0) { // propagate deregistration 这里表示root有父阶段且自己已经完成
                    phase = parent.doArrive(ONE_DEREGISTER);//父阶段中标识自己已经完成并且将参与者数量减1,未到达的参与者也减1
                    UNSAFE.compareAndSwapLong(this, stateOffset,//将当前的state,case自旋,置为EMPTY
                                              s, s | EMPTY);
                }
                else
                    phase = parent.doArrive(ONE_ARRIVAL);//当前线程不是最后一个完成的线程,将未到达的参与者数量减1即可
            }
            return phase;
        }
    }
}

4.留言

? 到了这里,其实AQS的源码基本已经覆盖了,对于AQS的源码也应该有了清楚的认知。总结就是:一个volatile 的state变量,两个等待队列(竞争队列,条件队列),通过cas的方式保证单变量的原子性。后续将会对Exchanger以及Phaser进行源码解析,到此基本AQS已经到了一个段落了。后续观看源码时,请注意多考虑一下多线程并发时可能出现的情况,去理解doug lea写代码的思路。

posted @ 2023-06-19 21:20  bug的自我救赎  阅读(0)  评论(0编辑  收藏  举报
回帖
    张三

    张三 (王者 段位)

    921 积分 (2)粉丝 (41)源码

     

    温馨提示

    亦奇源码

    最新会员