`
BrokenDreams
  • 浏览: 254662 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
68ec41aa-0ce6-3f83-961b-5aa541d59e48
Java并发包源码解析
浏览量:100413
社区版块
存档分类
最新评论

Jdk1.7 JUC源码增量解析(6)-Phaser

阅读更多

Jdk1.7 JUC源码增量解析(6)-Phaser

作者:大飞

 

功能简介:
  • Phaser是jdk1.7提供的类似于CyclicBarrier和CountDownLatch的同步机制。
  • 它支持更灵活的使用方式:1.使用过程中可以随时注册和注销参与者;2.不同于CyclicBarrier,分离出"到达"和"等待"机制;3.支持结束,默认情况下,当没有参与者的时候Phaser就结束了;4.支持层级Phaser结构;5.提供针对内部状态的监控方法;
源码分析:
  • 先看一下内部结构:
    /**
     * 主状态,分为4部分:
     *
     * 未到达计数  -- 还没有到达栅栏的参与者计数。  (bits  0-15)
     * parties     -- 栅栏全部参与者的计数。        (bits 16-31)
     * phase       -- 栅栏当前所处的阶段            (bits 32-62)
     * terminated  -- 栅栏的结束标记                (bit  63 / sign)
     *
     * 一个没有注册参与者的phaser的主状态中会有0个参与者计数
     * 和1个未到达计数。
     */
    private volatile long state;
    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 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  EMPTY           = 1;
       主状态是Phaser中的一个重要的域,它是一个long型值,内部包含了4部分内容:未到达栅栏的参与者的计数、栅栏的全部参与者计数、当前栅栏处于的阶段(和CyclicBarrier每次用完后会产生一个新的generation的行为类似)、结束标记。

       主状态这样设计(将状态封装到一个原子的long域)可以从两方面提高性能,一个是对状态的编解码简单高效、另一个是可以减小竞争窗口(空间)。 

 

    /**
     * 当前phaser的父phaser, 如果没有父phaser,这个域为null。
     */
    private final Phaser parent;
    /**
     * phaser树的根节点. 如果当前phaser不在一棵树内,这个域等于自身。
     */
    private final Phaser root;

 

    private final AtomicReference<QNode> evenQ;
    private final AtomicReference<QNode> oddQ;
    private AtomicReference<QNode> queueFor(int phase) {
        return ((phase & 1) == 0) ? evenQ : oddQ;
    }
       Phaser中使用Treiber Stack结构来保存等待线程,为了在一些情况下避免竞争,Phaser内部使用了2个Treiber Stack,evenQ和addQ,分别在内部phase为偶数和奇数下交替使用。
 

       再看下QNode这个类,先看下结构:

    static final class QNode implements ForkJoinPool.ManagedBlocker {
        final Phaser phaser;
        final int phase;
        final boolean interruptible;
        final boolean timed;
        boolean wasInterrupted;
        long nanos;
        long lastTime;
        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.lastTime = timed ? System.nanoTime() : 0L;
            thread = Thread.currentThread();
        }
       QNode内部结构很简单,就是保存了一些线程等待的相关信息,还有指向下一个QNode的域。这里要注意的是QNode实现了ForkJoinPool.ManagedBlocker,作用就是当包含ForkJoinWorkerThread的QNode阻塞的时候,ForkJoinPool内部会增加一个工作线程来保证并行度(具体的内容可以回头看一下ForkJoin框架的分析文章)。

      继续看下QNode中的方法,首先是isReleasable方法:

        public boolean isReleasable() {
            if (thread == null)
                return true;
            if (phaser.getPhase() != phase) {
                thread = null;
                return true;
            }
            if (Thread.interrupted())
                wasInterrupted = true;
            if (wasInterrupted && interruptible) {
                thread = null;
                return true;
            }
            if (timed) {
                if (nanos > 0L) {
                    long now = System.nanoTime();
                    nanos -= now - lastTime;
                    lastTime = now;
                }
                if (nanos <= 0L) {
                    thread = null;
                    return true;
                }
            }
            return false;
        }
       isReleasable方法中的逻辑比较简单:当QNode中的thread为null、或者和phaser的阶段值不相等、或者被中断、或者等待超时,方法都返回true。

       再看下block方法:

        public boolean block() {
            if (isReleasable())
                return true;
            else if (!timed)
                LockSupport.park(this);
            else if (nanos > 0)
                LockSupport.parkNanos(this, nanos);
            return isReleasable();
        }
       block方法就是一个阻塞的过程。
 
 
  • 通过一些示例来分析下主要功能源码。

       首先看一个示例,使用方式类似于Count为1的CountDownLatch:

	public static void main(String[] args) {
		
		final Phaser phaser = new Phaser(1);
		for(int i=0;i<10;i++){
			phaser.register();
			new Thread(new Runnable() {
				@Override
				public void run() {
					phaser.arriveAndAwaitAdvance();
					System.out.println(Thread.currentThread() +" start!!!!");
				}
			}).start();
		}
		try {
			TimeUnit.SECONDS.sleep(5);
			phaser.arriveAndDeregister();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
       上面的示例会在main线程启动后,sleep5秒,然后上面启动的10个线程才会打印。
 

       示例中首先构造了一个Phaser,我们先看下构造方法:

    /**
     * 创建一个没有初始参与者的phaser,默认没有父级phaser,初始
     * phase值为0。如果有任何线程想要使用这个phaser,都必须先
     * 注册这个phaser。
     */
    public Phaser() {
        this(null, 0);
    }
    /**
     * 创建一个有初始参与者(未到达)数量的phaser,默认没有父级phaser,初始
     * phase值为0。
     */
    public Phaser(int parties) {
        this(null, parties);
    }

    public Phaser(Phaser parent) {
        this(parent, 0);
    }
    /**
     * 创建一个有给定父级phaser和初始参与者(未到达)数量的phaser, 
     * 如果给定的父级phaser不为null,并且给定的参与者数量大于0, 
     * 当前的子phaser相当于注册了父phaser。
     */
    public Phaser(Phaser parent, int parties) {
        //parties不能超过65535
        if (parties >>> PARTIES_SHIFT != 0)
            throw new IllegalArgumentException("Illegal number of parties");
        int phase = 0;
        this.parent = parent;
        if (parent != null) {
            //如果父级Phaser不为空。
            final Phaser root = parent.root;
            this.root = root;
            //共享父级的线程等待队列。
            this.evenQ = root.evenQ;
            this.oddQ = root.oddQ;
            if (parties != 0)
                //如果当前phaser的参与者不为0,那么注册一个参与者到父级,注意这里是一个。
                phase = parent.doRegister(1);
        }
        else {
            //如果父级为空。
            //root就是自身,
            this.root = this;
            this.evenQ = new AtomicReference<QNode>();
            this.oddQ = new AtomicReference<QNode>();
        }
        this.state = (parties == 0) ? (long)EMPTY :
            ((long)phase << PHASE_SHIFT) |
            ((long)parties << PARTIES_SHIFT) |
            ((long)parties);
    }
       构造方法很简单,只要注意两点:1.当有父级Phaser的时候,子Phaser会共享父Phaser的线程等待队列。如果子Phaser的参与者不为0,那么会以一个参与者的身份注册到父Phaser上,注意是一个!!;2.最后初始化state的时候,如果没有参与者,state就是EMPTY,等于1。
 

       示例中接下来会在每次新建线程之前调用register方法来注册参与者,看下这个方法:

    /**
     * 添加一个新的未到达的参与者到当前phaser。如果当前正在onAdvance方法, 
     * 的执行过程中,这个方法会等待其完成再返回。如果当前phaser有父phaser,
     * 并且当前phaser之前没有注册的参与者,phaser会注册到父phaser上。 
     * 如果当前phaser结束了,那么方法不会产生任何作用,并返回一个负数。 
     */
    public int register() {
        return doRegister(1);
    }

       register内部调用的是doRegister,看下这个方法: 

    private int doRegister(int registrations) {
        //调整主状态,将给定的数值加到总参与者和未到达参数者数量上。
        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;
            if (registrations > MAX_PARTIES - parties)
                //注册的参与者数量和已存在的参与者数量加起来不能超过最大参与者数量。
                throw new IllegalStateException(badRegister(s));
            else if ((phase = (int)(s >>> PHASE_SHIFT)) < 0)
                //如果phaser已经结束,那么直接退出循环。
                break;
            else if (counts != EMPTY) {
                //如果不是第一个注册。
                if (parent == null || reconcileState() == s) {
                    if (unarrived == 0)
                        // 如果当前未到达数量为0,说明需要进入下一阶段了,这里要等待一下root进入下一阶段。             
                        root.internalAwaitAdvance(phase, null);
                    //否则原子更新主状态。
                    else if (UNSAFE.compareAndSwapLong(this, stateOffset,
                                                       s, s + adj))
                        break;
                }
            }
            else if (parent == null) {
                // 第一个root注册(没有父级)。
                // 算出下一个主状态。
                long next = ((long)phase << PHASE_SHIFT) | adj;
                // 原子更新主状态。
                if (UNSAFE.compareAndSwapLong(this, stateOffset, s, next))
                    break;
            }
            else {
                //第一个子phaser的注册,需要加锁。
                synchronized (this) {               
                    if (state == s) {               //检测一下状态有没有变化。
                        parent.doRegister(1);       //由于是第一次注册,所以需要向父类注册一下。
                        do {                        //更新到下一个主状态。
                            phase = (int)(root.state >>> PHASE_SHIFT);
                            // assert phase < 0 || (int)state == EMPTY;
                        } while (!UNSAFE.compareAndSwapLong
                                 (this, stateOffset, state,
                                  ((long)phase << PHASE_SHIFT) | adj));
                        break;
                    }
                }
            }
        }
        return phase;
    }
       总结一下doRegister方法:
              1.当前不是第一个注册者(参与者)。如果当前主状态中未到达数量为0,说明参与者已经全部到达栅栏,当前Phaser正在进入下一阶段过程中,需要等待这一过程完成(可能会阻塞);否则会原子更新当前的主状态,加一个总参与者数量和一个未到达参与者数量。(过程中如果parent不为null,需要调用reconcileState调整一下当前主状态,和root的主状态保持一致)
              2.当前是第一个注册者且当前Phaser没有父级Phaser。直接原子更新当前主状态,加一个总参与者数量和一个未到达参与者数量。
              3.当前是第一个注册者且当前Phaser有父级Phaser。需要加锁操作,首先向父级Phaser注册一个参与者,然后原子更新主状态,加一个总参与者数量和一个未到达参与者数量。
 

       doRegister方法中会调用reconcileState来调整状态,看下这个方法实现:

    private long reconcileState() {
        final Phaser root = this.root;
        long s = state;
        if (root != this) {
            int phase, u, p;
            // CAS root phase with current parties; possibly trip unarrived
            while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
                   (int)(s >>> PHASE_SHIFT) &&
                   !UNSAFE.compareAndSwapLong
                   (this, stateOffset, s,
                    s = (((long)phase << PHASE_SHIFT) |
                         (s & PARTIES_MASK) |
                         ((p = (int)s >>> PARTIES_SHIFT) == 0 ? EMPTY :
                          (u = (int)s & UNARRIVED_MASK) == 0 ? p : u))))
                s = state;
        }
        return s;
    }
       可见,这个方法要做的事情就是将当前Phaser和root Phaser的phase值调整为一致的。
 

       doRegister方法中,如果当前Phaser正在进入下一阶段过程中,需要等待这个过程完成,会调用internalAwaitAdvance方法,看下这个方法:

    /** cpu核数 */
    private static final int NCPU = Runtime.getRuntime().availableProcessors();
    /**
     * 单个参与者阻塞等待栅栏进入下一个阶段之前的自旋次数。
     * 在多核处理器下,一次性完全的阻塞和唤醒一大批线程通常比较慢,
     * 所以我们这里使用了一个可调整的自旋次数值在避免这种情况。
     * 当一个参与者线程在internalAwaitAdvance方法中阻塞之前发现了
     * 其他到达的线程,并且有cpu资源可用,那么这个参与者线程会在阻塞 
     * 之前自旋SPINS_PER_ARRIVAL或者更多次。
     */
    static final int SPINS_PER_ARRIVAL = (NCPU < 2) ? 1 : 1 << 8;

    private int internalAwaitAdvance(int phase, QNode node) {
        releaseWaiters(phase-1);          // 清空不用的等待线程队列(Treiber Stack)。
        boolean queued = false;           // 入队标识。
        int lastUnarrived = 0;            // 用于在发生变化时增加自旋次数。
        int spins = SPINS_PER_ARRIVAL;
        long s;
        int p;
        while ((p = (int)((s = state) >>> PHASE_SHIFT)) == phase) {
            if (node == null) {          
                int unarrived = (int)s & UNARRIVED_MASK;
                //如果未到达参与者数量发生了变化,且变化后的未到达数量小于cpu核数,需要增加自旋次数。
                if (unarrived != lastUnarrived &&
                    (lastUnarrived = unarrived) < NCPU)
                    spins += SPINS_PER_ARRIVAL;
                //获取并清除当前线程中断标记。
                boolean interrupted = Thread.interrupted();
                if (interrupted || --spins < 0) { 
                    //如果当前线程被中断,或者自旋次数用完。创建一个(不可中断的)节点。
                    node = new QNode(this, phase, false, false, 0L);
                    node.wasInterrupted = interrupted;
                }
            }
            else if (node.isReleasable()) // done or aborted
                break;
            else if (!queued) {           // 将节点加入队列首部。
                AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
                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);
                } catch (InterruptedException ie) {
                    node.wasInterrupted = true;
                }
            }
        }
        if (node != null) {
            if (node.thread != null)
                node.thread = null;       // avoid need for unpark()
            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;
    }
       internalAwaitAdvance中的主要逻辑过程就是当前(参与者)线程等待Phaser进入下一个阶段(就是phase值变化)。有些细节需要注意一下。
       如果传入的node为null,过程如下:
       第1步,等待分两个阶段,自旋等待和阻塞等待,首先自旋给定的次数,如果自旋过程中未到达参与者数量发生变化,且变化后的为未到达参与者数量小于CPU处理器核数,那么自选次数会增加SPINS_PER_ARRIVAL次。如果自旋次数用完后或者当前线程被中断了,那么会创建一个不可中断模式的节点,节点中保存当前线程及其他信息。
       第2步,将上面创建的节点加入线程等待队列的首部(类似于压栈,因为线程等待队列就是Treiber Stack)。
       第3步,当前线程开始阻塞等待。
       第4步,当前线程被唤醒后,如果是不可中断模式的节点,需要向上层传递中断状态;如果当前phaser还是没有进入下一阶段,那么调用abortWait,做放弃等待操作。
 
       如果传入的node不为null,过程和上面类似,只是没有第1步。 

       注意整个internalAwaitAdvance过程的前后都会清空一下当前不用的等待线程队列(两个奇偶队列交替使用),看下这个方法:

    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) &&
                (t = q.thread) != null) {
                q.thread = null;
                LockSupport.unpark(t);
            }
        }
    }
       逻辑很简单,就是把等待线程队列里面的节点都移除了,如果节点有线程的话,将线程唤醒。
 

       internalAwaitAdvance中还可能会调用一个放弃等待的abortWait方法,看下:

    private int abortWait(int phase) {
        AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
        for (;;) {
            Thread t;
            QNode q = head.get();
            int p = (int)(root.state >>> PHASE_SHIFT);
            if (q == null || ((t = q.thread) != null && q.phase == p))
                return p;
            if (head.compareAndSet(q, q.next) && t != null) {
                q.thread = null;
                LockSupport.unpark(t);
            }
        }
    }
       这个方法和releaseWaiters方法有些区别:
       releaseWaiters方法是用来清空当前不适用的等待线程队列的;abortWait方法是将当前正在使用的队列中由于超时或者中断不在等待当前phaser的下一阶段的节点移除。
 
 

       再回头看我们的示例,for循环中新建的线程在运行时会先调用arriveAndAwaitAdvance方法,然后会在这个方法上等待,直到主线程调用了arriveAndDeregister。看下arriveAndAwaitAdvance这个方法:

    public int arriveAndAwaitAdvance() {
        final Phaser root = this.root;
        for (;;) {
            //获取主状态
            long s = (root == this) ? state : reconcileState();
            //获取phase值
            int phase = (int)(s >>> PHASE_SHIFT);
            int counts = (int)s;
            //获取当前未到达参与者计数,就是之前的未到达计数减1。
            int unarrived = (counts & UNARRIVED_MASK) - 1;
            if (phase < 0)
                return phase; //如果当前phaser已经结束,退出。
            else if (counts == EMPTY || unarrived < 0) {
                if (reconcileState() == s)
                    throw new IllegalStateException(badArrive(s)); //非法状态。
            }
            //主状态中未到达参与者的计数减1。
            else if (UNSAFE.compareAndSwapLong(this, stateOffset, s,
                                               s -= ONE_ARRIVAL)) {
                if (unarrived != 0)
                    //如果还有未到达的参与者,等待。
                    return root.internalAwaitAdvance(phase, null);
                if (root != this)
                    //如果当前是子级Phaser,要等待父级进入下一阶段。
                    return parent.arriveAndAwaitAdvance();
                long n = s & PARTIES_MASK;  // base of next state
                //这里算出来的是总参与者的数量。
                int nextUnarrived = (int)n >>> PARTIES_SHIFT;
                //调用onAdvance方法。
                if (onAdvance(phase, nextUnarrived))
                    //如果onAdvance方法返回true,给主状态中设置结束标记。
                    n |= TERMINATION_BIT;
                else if (nextUnarrived == 0)
                    //如果总参与者数量变为0,那么将主状态设置为没有参与者的特殊状态。
                    n |= EMPTY;
                else
                    //否则,重置未到达参与者数量。
                    n |= nextUnarrived;
                //算出下一个phase值。
                int nextPhase = (phase + 1) & MAX_PHASE;
                //设置到主状态上。
                n |= (long)nextPhase << PHASE_SHIFT;
                //原子更新主状态。
                if (!UNSAFE.compareAndSwapLong(this, stateOffset, s, n))
                    //如果发生竞争,返回phase值,如果当前phaser结束,返回负数。
                    return (int)(state >>> PHASE_SHIFT); // terminated
                //清空上一阶段使用的线程等待队列。
                releaseWaiters(phase);
                //最后返回上面算出来的nextPhase值。
                return nextPhase;
            }
        }
    }
       arriveAndAwaitAdvance方法中的主要逻辑如下:
              首先将主状态中的未到达参与者数量减1,然后判断未到达参与者数量是否为0。如果不为0,当前线程会等待其他参与者到来;如果为0,说明当前(线程)是最后一个参与者,那么会继续算出下一个阶段的主状态,然后更新到Phaser中。计算过程中会通过调用onAdvance方法,判断当前Phaser是否结束,还会重置未到达参与者数量等。
 

       看一下arriveAndAwaitAdvance方法中调用的onAdvance方法:

    protected boolean onAdvance(int phase, int registeredParties) {
        return registeredParties == 0;
    }
       onAdvance方法的作用就是来控制Phaser是否结束,默认行为是当总参与者数量为0时,Phaser就结束了。具体使用时可以覆盖这个方法,实现合适的策略来控制Phaser的结束时机。
 

       回到示例的最后,主线程休眠5秒中,然后调用了arriveAndDeregister方法,看下这个方法:

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

       这个方法表示一个参与者到达栅栏,并且将自己从phaser上注销。内部调用了doArrive方法:

    private int doArrive(boolean deregister) {
        int adj = deregister ? ONE_ARRIVAL|ONE_PARTY : ONE_ARRIVAL;
        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) {
                if (root == this || reconcileState() == s)
                    throw new IllegalStateException(badArrive(s));
            }
            else if (UNSAFE.compareAndSwapLong(this, stateOffset, s, s-=adj)) {
                if (unarrived == 0) {
                    long n = s & PARTIES_MASK;  // base of next state
                    int nextUnarrived = (int)n >>> PARTIES_SHIFT;
                    if (root != this)
                        //这里注意下:如果当前子phaser中没有参与者了,就要于从父phaser中将当前子phaser注销。
                        return parent.doArrive(nextUnarrived == 0);
                    if (onAdvance(phase, nextUnarrived))
                        n |= TERMINATION_BIT;
                    else if (nextUnarrived == 0)
                        n |= EMPTY;
                    else
                        n |= nextUnarrived;
                    n |= (long)((phase + 1) & MAX_PHASE) << PHASE_SHIFT;
                    UNSAFE.compareAndSwapLong(this, stateOffset, s, n);
                    releaseWaiters(phase);
                }
                return phase;
            }
        }
    }
       可见,这个方法中的逻辑和arriveAndAwaitAdvance方法类似,区别是如果参数deregister为true,会在主状态中减去一个参与者计数。
 
       示例中使用到的方法都分析过了,再回头看示例,会发现逻辑细节也清晰了:
       首先,构造了有1个参与者的Phaser。
       其次,开启10个线程,每个线程作为1个参与者注册到上面创建的Phaser上。然后启动线程,在线程执行具体逻辑前等待其他参与者到达栅栏(arriveAndAwaitAdvance)。
       最后,主线程到达栅栏并将自己注销。这时,所有的参与者(一共11个)都已经到达栅栏,上面的10个参与者(线程)就可以通过栅栏,执行具体逻辑了。
 

       再看一个示例,使用方式类似于Count为N的CountDownLatch:

	public static void main(String[] args) {
		final Phaser phaser = new Phaser();
		for(int i=0;i<10;i++){
			phaser.register();
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						TimeUnit.SECONDS.sleep(new Random().nextInt(5));
						System.out.println(Thread.currentThread() +" is ready!");
						phaser.arriveAndAwaitAdvance();
						System.out.println(Thread.currentThread() +" start!!!!");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}).start();
		}
	}
       这个示例要更简单一些,就是等待所有的线程都ready后,然后一起start。涉及到的Phaser方法都分析过了。
 

       继续看一个示例,和第一个示例差不多,但有一点区别:第一个示例中线程只执行了一次逻辑,现在要求线程执行若干次逻辑:

	public static void main(String[] args) {
		final Phaser phaser = new Phaser(1){
			protected boolean onAdvance(int phase, int registeredParties) {
				System.out.println("now phase is " + phase);
				return phase >= 5 || registeredParties == 0;
			}
		};
		for(int i=0;i<5;i++){
			phaser.register();
			final int time = i;
			new Thread(new Runnable() {
				@Override
				public void run() {
					do{
						phaser.arriveAndAwaitAdvance();
						System.out.println(Thread.currentThread() +" start-"+time+"!!!!");
					}while(!phaser.isTerminated());
				}
			}).start();
		}
		try {
			TimeUnit.SECONDS.sleep(5);
			System.out.println("arriveAndDeregister...");
			phaser.arriveAndDeregister();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
       本示例和第一个示例区别只是覆盖了onAdvance方法,加上了阶段限制逻辑:当phase大于等于5时,Phaser就结束了,也就是说,线程里面的逻辑会执行6次(phase从0开始)。
       前面提高过,第一个示例对Phaser的使用方式类似于Count为1的CountDownLatch;而本示例中的Phaser在第一次使用时相当于Count为1的CountDownLatch,当主线程到达并注销自己(相当于countDown),前面启动的子线程就会(通过栅栏)执行逻辑了。但随后的使用又相当于是一个CyclicBarrier,示例中第一次的参与者包括主线程,一共是6个。主线程在Phaser中注销后,后面就只有5个参与者,所以每当这个5个线程都达到栅栏时,它们会一起通过,所以相当于一个CyclicBarrier了。同时我们可以看到,onAdvance中也可以定制类似于CyclicBarrier的barrierAction的逻辑,我们这里是打印了一个语句。

       示例输出如下:

arriveAndDeregister...
now phase is 0
Thread[Thread-4,5,main] start-4!!!!
Thread[Thread-1,5,main] start-1!!!!
Thread[Thread-0,5,main] start-0!!!!
Thread[Thread-2,5,main] start-2!!!!
Thread[Thread-3,5,main] start-3!!!!
now phase is 1
Thread[Thread-0,5,main] start-0!!!!
Thread[Thread-4,5,main] start-4!!!!
Thread[Thread-2,5,main] start-2!!!!
Thread[Thread-3,5,main] start-3!!!!
Thread[Thread-1,5,main] start-1!!!!
now phase is 2
Thread[Thread-1,5,main] start-1!!!!
Thread[Thread-3,5,main] start-3!!!!
Thread[Thread-2,5,main] start-2!!!!
Thread[Thread-4,5,main] start-4!!!!
Thread[Thread-0,5,main] start-0!!!!
now phase is 3
Thread[Thread-0,5,main] start-0!!!!
Thread[Thread-3,5,main] start-3!!!!
Thread[Thread-1,5,main] start-1!!!!
Thread[Thread-2,5,main] start-2!!!!
Thread[Thread-4,5,main] start-4!!!!
now phase is 4
Thread[Thread-4,5,main] start-4!!!!
Thread[Thread-0,5,main] start-0!!!!
Thread[Thread-1,5,main] start-1!!!!
Thread[Thread-3,5,main] start-3!!!!
Thread[Thread-2,5,main] start-2!!!!
now phase is 5
Thread[Thread-2,5,main] start-2!!!!
Thread[Thread-3,5,main] start-3!!!!
Thread[Thread-4,5,main] start-4!!!!
Thread[Thread-0,5,main] start-0!!!!
Thread[Thread-1,5,main] start-1!!!!

                  

 

 

  • 最后,看一下示例中未涉及到的代码。
    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);
    }

       这组方法可以从主状态中获取各个状态,是一组"拆包"方法。在具体功能方法内部可能不会调用这些方法,而是手工内联进去。

 

 

    private String badArrive(long s) {
        return "Attempted arrival of unregistered party for " +
            stateToString(s);
    }

    private String badRegister(long s) {
        return "Attempt to register more than " +
            MAX_PARTIES + " parties for " + stateToString(s);
    }
    private String stateToString(long s) {
        return super.toString() +
            "[phase = " + phaseOf(s) +
            " parties = " + partiesOf(s) +
            " arrived = " + arrivedOf(s) + "]";
    }

       这badArrice和badRegister方法用于在逻辑中出现非法参与注册情况时,提供提示消息。stateToString方法将state转化为易懂的字符串形式,用于支持前面两个方法和toString方法。 

 

 

    public int bulkRegister(int parties) {
        if (parties < 0)
            throw new IllegalArgumentException();
        if (parties == 0)
            return getPhase();
        return doRegister(parties);
    }
    public final int getPhase() {
        return (int)(root.state >>> PHASE_SHIFT);
    }

       相对于register的批量注册方法。 

 

 

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

       和arriveAndDeregister类似,只是不会注销当前参与者。 

 

 

    public int awaitAdvance(int phase) {
        final Phaser root = this.root;
        long s = (root == this) ? state : reconcileState();
        int p = (int)(s >>> PHASE_SHIFT);
        if (phase < 0)
            return phase;
        if (p == phase)
            return root.internalAwaitAdvance(phase, null);
        return p;
    }

       等待phase值表示的阶段,如果当前phase和给定的phase不一致,直接返回当前的phase值。 

 

 

    public int awaitAdvanceInterruptibly(int phase)
        throws InterruptedException {
        final Phaser root = this.root;
        long s = (root == this) ? state : reconcileState();
        int p = (int)(s >>> PHASE_SHIFT);
        if (phase < 0)
            return phase;
        if (p == phase) {
            QNode node = new QNode(this, phase, true, false, 0L);
            p = root.internalAwaitAdvance(phase, node);
            if (node.wasInterrupted)
                throw new InterruptedException();
        }
        return p;
    }

       awaitAdvance方法逻辑一样,但支持中断。 

 

 

    public int awaitAdvanceInterruptibly(int phase,
                                         long timeout, TimeUnit unit)
        throws InterruptedException, TimeoutException {
        long nanos = unit.toNanos(timeout);
        final Phaser root = this.root;
        long s = (root == this) ? state : reconcileState();
        int p = (int)(s >>> PHASE_SHIFT);
        if (phase < 0)
            return phase;
        if (p == phase) {
            QNode node = new QNode(this, phase, true, true, nanos);
            p = root.internalAwaitAdvance(phase, node);
            if (node.wasInterrupted)
                throw new InterruptedException();
            else if (p == phase)
                throw new TimeoutException();
        }
        return p;
    }

       awaitAdvance方法逻辑一样,但支持中断和超时。 

 

 

    public void forceTermination() {
        // Only need to change root state
        final Phaser root = this.root;
        long s;
        while ((s = root.state) >= 0) {
            //给主状态中添加结束标记。
            if (UNSAFE.compareAndSwapLong(root, stateOffset,
                                          s, s | TERMINATION_BIT)) {
                //清空奇偶线程等待队列。
                releaseWaiters(0);
                releaseWaiters(1);
                return;
            }
        }
    }
       强制结束Phaser。
 
 

       最后看一些支持监控的方法:

    public final int getPhase() {
        return (int)(root.state >>> PHASE_SHIFT);
    }

    public int getRegisteredParties() {
        return partiesOf(state);
    }

    public int getArrivedParties() {
        return arrivedOf(reconcileState());
    }

    public int getUnarrivedParties() {
        return unarrivedOf(reconcileState());
    }

    public Phaser getParent() {
        return parent;
    }

    public Phaser getRoot() {
        return root;
    }

    public boolean isTerminated() {
        return root.state < 0L;
    }
       方法都非常简单,不啰嗦了。
 

       OK,JDK1.7 Phaser的代码解析完毕!  

 

 

       参见:Jdk1.6 JUC源码解析(9)-CountDownLatch

       参见:Jdk1.6 JUC源码解析(11)-CyclicBarrier

       参见:Jdk1.7 JUC源码增量解析(5)-ForkJoin-ForkJoin框架其他过程及方法

 

 

 

分享到:
评论

相关推荐

    jdk1.7官网 jdk-7u80-linux-x64.tar.gz.zip

    在给定的压缩包文件"jdk1.7官网 jdk-7u80-linux-x64.tar.gz.zip"中,包含的主要内容是JDK 7u80的Linux 64位版本。这个版本是针对64位Linux操作系统的,确保在该环境下能够顺利进行Java开发工作。文件名"jdk-7u80-...

    jdk1.7 64位官方版 jdk-7u79-linux-x64.tar.gz

    1. 首先,下载名为“jdk-7u79-linux-x64.tar.gz”的压缩文件,这是针对Linux 64位系统的JDK 1.7的归档文件。 2. 使用解压命令(如tar -zxvf jdk-7u79-linux-x64.tar.gz)将内容解压到指定目录。 3. 设置环境变量,...

    java-jdk1.7-jdk-7u80-windows-x64.zip

    安装Java JDK 1.7 on Windows x64的步骤非常简单,只需双击下载的“jdk-7u80-windows-x64.exe”文件,然后按照安装向导进行操作。安装过程中,记得选择合适的安装路径,并勾选“添加Java到系统环境变量”选项,以便...

    jdk-1.7-windows-32-1

    4部分: jdk-1.7-windows-32-1 jdk-1.7-windows-32-2 jdk-1.7-windows-32-3 jdk-1.7-windows-32-4

    jdk-1.7-windows-64-02

    三部分: jdk-1.7-windows-64-01 jdk-1.7-windows-64-02 jdk-1.7-windows-64-03

    jdk1.7 64位官方正式版 jdk-7u71-macosx-x64.dmg

    jdk1.7 64位官方正式版 jdk-7u71-macosx-x64.dmg

    jdk1.7版本-----------

    压缩包中的文件`[www.java1234.com]jdk-7u67-windows-x64.exe`是JDK 1.7的64位Windows版安装程序。安装这个版本的JDK后,开发者可以在Windows操作系统上进行Java 7的开发工作,包括编写、编译和运行Java程序,以及...

    jdk-1.7-linux-32-1

    三部分: jdk-1.7-linux-32-1 jdk-1.7-linux-32-2 jdk-1.7-linux-32-3

    jdk-1.7-linux-64-03

    三部分: jdk-1.7-linux-64-01 jdk-1.7-linux-64-02 jdk-1.7-linux-64-03

    jdk1.7 64位官方正式版 jdk-7u79-linux-x64

    - 解压下载的`jdk-7u79-linux-x64`压缩包到适当目录。 - 配置环境变量`JAVA_HOME`,`PATH`和`CLASSPATH`,使系统能够找到JDK。 - 使用`java -version`命令检查安装是否成功。 5. **开发和运行Java程序**: - ...

    jdk1.7 64位 Linux版 jdk-7u79-linux-x64.tar.gz

    标题"jdk1.7 64位 Linux版 jdk-7u79-linux-x64.tar.gz"明确指出我们讨论的是Java Development Kit (JDK) 的1.7版本,专为64位Linux操作系统设计。文件名"jdk-7u79-linux-x64.tar.gz"表明这是一个压缩文件,采用tar...

    java jdk1.7源码包,用于centos7使用jdk1.7编译openjdk1.8的 1.7版本

    Java JDK 1.7源码包是用于在CentOS 7操作系统上进行OpenJDK 1.8编译的重要资源。这个源码包包含了Java Development Kit的1.7版本,通常被称为JDK 7,它是Oracle公司发布的Java编程语言和Java平台标准版的一个实现。...

    JDK1.7 64位 官方正版 jdk-7u80-macosx-x64.dmg

    文件比较大,给了百度云连接,直接下载 JDK1.7 64位 官方正版 jdk-7u80-macosx-x64.dmg 官方网站版本 苹果64位操作系统JDK

    jdk-1.7-linux-64-01

    三部分: jdk-1.7-linux-64-01 jdk-1.7-linux-64-02 jdk-1.7-linux-64-03

    jdk1.7 官方正式版32位下载(jdk-7u45-windows-i586.exe)

    jdk1.7 官方正式版32位下载 JDK详细介绍 JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK)。 SE(J2SE),standard edition,标准版,是我们通常用的一个版本,从JDK 5.0开始,改名为Java SE。 EE(J2EE)...

    springboot+mybatis+jdk1.7

    标题 "springboot+mybatis+jdk1.7" 指的是一个基于Spring Boot、MyBatis框架,并使用Java Development Kit 1.7版本构建的Web应用项目。这个项目已经搭建完成,具备基本的结构,方便开发者快速启动一个新的Java Web...

    jdk-1.7-windows-32-2

    4部分: jdk-1.7-windows-32-1 jdk-1.7-windows-32-2 jdk-1.7-windows-32-3 jdk-1.7-windows-32-4

    jdk-1.7-java-7-openjdk-amd64.zip

    标题中的"jdk-1.7-java-7-openjdk-amd64.zip"表明这是一个Java开发工具包(JDK)的压缩文件,版本为1.7,适用于AMD64架构的Linux系统。OpenJDK是Java Development Kit的一个开源实现,由Oracle公司支持并维护。这个...

    jdk1.7 32位官方正式版 jdk-7u79-windows-i586 下载

    jdk-7u79-windows-i586.exe JDK7 稳定版 源官方下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html

Global site tag (gtag.js) - Google Analytics