SynchronousQueue 源码分析

SynchronousQueue

SynchronousQueue 中每一个插入操作必须等待一个与之配对的删除操作,反之亦然。
SynchronousQueue 没有任何内部容量。
SynchronousQueue 非常适合于线程之间交换信息,均衡生产者与消费者的处理速率。

创建实例

    /**
     * Shared internal API for dual stacks and queues.
     */
    abstract static class Transferer<E> {
        /**
         *  执行一个 put 或 take 操作
         *
         * @param e 1)值为 null,则表示这是一个 take 操作
         *          2)值不为 null,则表示这是一个 put 操作
         * @param timed 操作的超时时间
         * @param nanos 以纳秒为单位
         * @return  1)值为 null 表示超时或线程被中断
         *          2)值不为 null,表示插入或读取的目标元素
         */
        abstract E transfer(E e, boolean timed, long nanos);
    }

    /**
     *  超时等待前的自旋次数
     */
    static final int MAX_TIMED_SPINS =
            Runtime.getRuntime().availableProcessors() < 2 ? 0 : 32;

    /**
     *  阻塞等待前的自旋次数
     */
    static final int MAX_UNTIMED_SPINS = SynchronousQueue.MAX_TIMED_SPINS * 16;

    /**
     *  超时时间小于 1000 纳秒时,自旋比阻塞等待效率高
     */
    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;

    /**
     *  转移接口
     */
    private transient volatile Transferer<E> transferer;

    /**
     *  创建一个非公平的同步队列
     */
    public SynchronousQueue() {
        this(false);
    }

    /**
     *  fair==true,创建一个公平的同步队列,最先等待的最先释放
     *  fair==false,创建一个非公平的同步队列
     */
    public SynchronousQueue(boolean fair) {
        transferer = fair ? new TransferQueue<>() : new TransferStack<>();
    }

添加元素

  • 将目标元素添加到同步队列,如果当前没有消费者,则阻塞等待
    /**
     *  将目标元素添加到同步队列,如果当前没有消费者,则阻塞等待
     */
    @Override
    public void put(E e) throws InterruptedException {
        if (e == null) {
            throw new NullPointerException();
        }
        if (transferer.transfer(e, false, 0) == null) {
            Thread.interrupted();
            throw new InterruptedException();
        }
    }

    /** Dual stack */
    static final class TransferStack<E> extends Transferer<E> {
        /** 节点代表一个未完成的消费者 */
        static final int REQUEST    = 0;
        /** 节点代表一个未完成的生产者 */
        static final int DATA       = 1;
        /** 节点正在完成一个匹配的操作 */
        static final int FULFILLING = 2;

        /** Node class for TransferStacks. */
        static final class SNode {
            // 堆栈的下一个节点
            volatile SNode next;
            // 与当前节点匹配的对偶节点
            volatile SNode match;
            // 当前节点驻留的线程
            volatile Thread waiter;
            // 如果是数据节点则非空,如果是请求节点则为 null
            Object item;
            // 当前节点的状态
            int mode;

            SNode(Object item) {
                this.item = item;
            }

            /**
             *  参数原子更新 next 节点
             */
            boolean casNext(SNode cmp, SNode val) {
                return cmp == next &&
                        SNode.SNEXT.compareAndSet(this, cmp, val);
            }

            /**
             *  尝试将目标节点匹配给当前节点,如果成功则唤醒驻留在当前节点的线程
             */
            boolean tryMatch(SNode s) {
                // 尝试设置匹配节点为 s
                if (match == null &&
                        SNode.SMATCH.compareAndSet(this, null, s)) {
                    // 读取驻留线程
                    final Thread w = waiter;
                    if (w != null) {    // waiters need at most one unpark
                        waiter = null;
                        // 唤醒驻留线程
                        LockSupport.unpark(w);
                    }
                    // 匹配成功返回 true
                    return true;
                }
                return match == s;
            }

            /**
             *  将匹配节点设置为 this 表示节点被删除
             */
            void tryCancel() {
                SNode.SMATCH.compareAndSet(this, null, this);
            }

            /**
             *  当前节点已经被取消
             * created by ZXD at 8 Dec 2018 T 11:11:25
             */
            boolean isCancelled() {
                return match == this;
            }

            // VarHandle mechanics
            private static final VarHandle SMATCH;
            private static final VarHandle SNEXT;
            static {
                try {
                    final MethodHandles.Lookup l = MethodHandles.lookup();
                    SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
                    SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
                } catch (final ReflectiveOperationException e) {
                    throw new Error(e);
                }
            }
        }  
    
        /** 堆栈顶部元素 */
        volatile SNode head;

        /**
         * Puts or takes an item.
         */
        @Override
        @SuppressWarnings("unchecked")
        E transfer(E e, boolean timed, long nanos) {
            /**
             *  1)如果堆栈为空或包含相同类型的节点,则新建节点并入栈,阻塞等待。
             *  2)如果堆栈中包含对偶节点,则将一个对偶节点入栈,
             *      并同时弹出新增节点及与其匹配的节点。
             *  3)如果堆栈顶部已经持有对偶节点,则帮助它们弹出堆栈。
             */
            SNode s = null; // constructed/reused as needed
            // 计算节点模式
            final int mode = e == null ? TransferStack.REQUEST : TransferStack.DATA;
            for (;;) {
                // 读取栈顶节点
                SNode h = head;
                // 1)堆栈为空或栈顶元素和新增节点模式一致
                if (h == null || h.mode == mode) {  // empty or same-mode
                    // 1-1)如果设置了超时时间,并且已经超时
                    if (timed && nanos <= 0L) {     // can't wait
                        // 头节点不为 null && 头节点已经被取消
                        if (h != null && h.isCancelled()) {
                            // 尝试原子更新栈顶节点
                            casHead(h, h.next);     // pop cancelled node
                        } else {
                            // 删除栈顶后返回 null
                            return null;
                        }
                        // 1-2)尝试将新节点入栈
                    } else if (casHead(h, s = TransferStack.snode(s, e, h, mode))) {
                        // 尝试在指定的超时时间内等待对偶节点
                        final SNode m = awaitFulfill(s, timed, nanos);
                        // 线程超时或被其他线程中断
                        if (m == s) {               // wait was cancelled
                            // 清除新增节点
                            clean(s);
                            return null;
                        }
                        // 当前节点和对偶节点位于栈顶前两个位置,则弹出它们
                        if ((h = head) != null && h.next == s)
                        {
                            casHead(h, s.next);     // help s's fulfiller
                        }
                        /**
                         *  1)新值的是请求节点,则返回对偶节点的数据值
                         *  2)新值的是数据节点,则返回其持有的数据
                         */
                        return (E) (mode == TransferStack.REQUEST ? m.item : s.item);
                    }
                // 2)头节点不是 fulFill 节点   
                } else if (!TransferStack.isFulfilling(h.mode)) { // try to fulfill
                    // 1)头节点已经被取消
                    if (h.isCancelled()) {
                        // 则重新写入头结点
                        casHead(h, h.next);         // pop and retry
                    // 2)尝试写入一个 fulFill 节点到栈顶   
                    } else if (casHead(h, s=TransferStack.snode(s, e, h, TransferStack.FULFILLING|mode))) {
                        for (;;) { // loop until matched or waiters disappear
                            // 读取匹配节点
                            final SNode m = s.next;       // m is s's match
                            // 已经不存在等待节点【被其他线程帮助弹出了】
                            if (m == null) {        // all waiters are gone
                                // 写入头节点
                                casHead(s, null);   // pop fulfill node
                                s = null;           // use new node next time
                                break;              // restart main loop
                            }
                            // 读取匹配节点的后置节点
                            final SNode mn = m.next;
                            // 如果仍处于匹配模式
                            if (m.tryMatch(s)) {
                                // 同时弹出这两个节点
                                casHead(s, mn);     // pop both s and m
                                /**
                                 *  1)新值的是请求节点,则返回对偶节点的数据值
                                 *  2)新值的是数据节点,则返回其持有的数据
                                 */ 
                                return (E) (mode == TransferStack.REQUEST ? m.item : s.item);
                            }
                            else {
                                s.casNext(m, mn);   // help unlink
                            }
                        }
                    }
                // 3)头结点是一个 fulFill 节点,则帮助将它和它的对偶节点出栈   
                } else {                            // help a fulfiller
                    final SNode m = h.next;               // m is h's match
                    if (m == null) {
                        casHead(h, null);           // pop fulfilling node
                    } else {
                        final SNode mn = m.next;
                        if (m.tryMatch(h)) {
                            casHead(h, mn);         // pop both h and m
                        }
                        else {
                            h.casNext(m, mn);       // help unlink
                        }
                    }
                }
            }
        }

        /**
         *  尝试原子更新头结点
         * created by ZXD at 8 Dec 2018 T 10:56:47
         * @param h
         * @param nh
         * @return
         */
        boolean casHead(SNode h, SNode nh) {
            return h == head &&
                    TransferStack.SHEAD.compareAndSet(this, h, nh);
        }

        /**
         *  将节点加入栈顶
         */
        static SNode snode(SNode s, Object e, SNode next, int mode) {
            // 如果是新增节点
            if (s == null) {
                // 则创建节点
                s = new SNode(e);
            }
            // 写入模式
            s.mode = mode;
            // 写入后置节点
            s.next = next;
            return s;
        }

        /**
         *  线程执行自旋或阻塞等待,直到堆栈中写入一个对偶节点、线程超时、被其他线程中断
         *
         * @param s 等待节点
         * @param timed 是否是超时模式
         * @param nanos 超时纳秒
         * @return  1)出现对偶节点,则返回对偶节点
         *          2)线程超时或被中断,则返回 s
         */
        SNode awaitFulfill(SNode s, boolean timed, long nanos) {
            /*
             * When a node/thread is about to block, it sets its waiter
             * field and then rechecks state at least one more time
             * before actually parking, thus covering race vs
             * fulfiller noticing that waiter is non-null so should be
             * woken.
             *
             * When invoked by nodes that appear at the point of call
             * to be at the head of the stack, calls to park are
             * preceded by spins to avoid blocking when producers and
             * consumers are arriving very close in time.  This can
             * happen enough to bother only on multiprocessors.
             *
             * The order of checks for returning out of main loop
             * reflects fact that interrupts have precedence over
             * normal returns, which have precedence over
             * timeouts. (So, on timeout, one last check for match is
             * done before giving up.) Except that calls from untimed
             * SynchronousQueue.{poll/offer} don't check interrupts
             * and don't wait at all, so are trapped in transfer
             * method rather than calling awaitFulfill.
             */
            // 计算截止时间
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            // 读取当前线程
            final Thread w = Thread.currentThread();
            // 计算自旋次数
            int spins = shouldSpin(s)
                    ? timed ? SynchronousQueue.MAX_TIMED_SPINS : SynchronousQueue.MAX_UNTIMED_SPINS
                            : 0;
            for (;;) {
                // 线程已经被中断
                if (w.isInterrupted()) {
                    // 则尝试删除节点
                    s.tryCancel();
                }
                // 读取匹配节点
                final SNode m = s.match;
                /**
                 *  如果存在匹配节点,则返回它
                 *  1)节点本身
                 *  2)对偶节点
                 */
                if (m != null) {
                    return m;
                }
                // 如果是超时模式
                if (timed) {
                    // 计算剩余时间
                    nanos = deadline - System.nanoTime();
                    if (nanos <= 0L) {
                        // 已经超时,则尝试删除节点
                        s.tryCancel();
                        continue;
                    }
                }
                // 1)尝试进行自旋
                if (spins > 0) {
                    // 线程执行自旋
                    Thread.onSpinWait();
                    // 重新计算值
                    spins = shouldSpin(s) ? spins - 1 : 0;
                }
                // 2)节点的驻留线程为 null
                else if (s.waiter == null) {
                    // 写入自旋线程
                    s.waiter = w; // establish waiter so can park next iter
                // 3)如果不是超时阻塞   
                } else if (!timed) {
                    // 阻塞当前线程
                    LockSupport.park(this);
                // 4)超时时间 > 1000 纳秒 
                } else if (nanos > SynchronousQueue.SPIN_FOR_TIMEOUT_THRESHOLD) {
                    // 超时阻塞当前线程
                    LockSupport.parkNanos(this, nanos);
                }
            }
        }

        /**
         * Unlinks s from the stack.
         */
        void clean(SNode s) {
            s.item = null;   // forget item
            s.waiter = null; // forget thread
            
            // 读取后置节点
            SNode past = s.next;
            // 如果后置节点也被取消了
            if (past != null && past.isCancelled()) {
                // 更新终止节点
                past = past.next;
            }

            /**
             *  从头部开始遍历,删除已经取消的节点,
             *  1)直到发现一个未取消的节点 ||
             *  2)一直遍历到 past 为止
             */
            SNode p;
            while ((p = head) != null && p != past && p.isCancelled()) {
                casHead(p, p.next);
            }
            
            // 发现了一个未取消的节点,从未取消的节点开始又执行一次清除操作
            while (p != null && p != past) {
                // 读取后置节点
                final SNode n = p.next;
                // 后置节点已经取消
                if (n != null && n.isCancelled()) {
                    // 则将其踢除
                    p.casNext(n, n.next);
                } else {
                    // 处理下一个节点
                    p = n;
                }
            }
        }
    }
  • 如果队列头部是一个 take 操作,则将当前元素传递给它,并返回 true,否则立刻返回 false
    /**
     *  如果栈顶是一个 take 操作,则将当前元素传递给它,并返回 true,否则立刻返回 false
     */
    @Override
    public boolean offer(E e) {
        if (e == null) {
            throw new NullPointerException();
        }
        return transferer.transfer(e, true, 0) != null;
    }
  • 尝试在指定的超时时间内将目标元素 e 传递给队列头部的一个 take 操作,传递成功则返回 true,否则返回 false。
    /**
     *  尝试在指定的超时时间内将目标元素 e 传递给一个 take 操作,
     *  传递成功则返回 true,否则返回 false
     */
    @Override
    public boolean offer(E e, long timeout, TimeUnit unit)
            throws InterruptedException {
        if (e == null) {
            throw new NullPointerException();
        }
        if (transferer.transfer(e, true, unit.toNanos(timeout)) != null) {
            return true;
        }
        // 线程未被中断,则返回 false;否则抛出 InterruptedException 异常
        if (!Thread.interrupted()) {
            return false;
        }
        throw new InterruptedException();
    }

读取元素

  • 移除并获取队列头元素,如果无可用元素,则阻塞等待
    /**
     *  移除并获取栈顶元素,如果无可用元素,则阻塞等待
     */
    @Override
    public E take() throws InterruptedException {
        final E e = transferer.transfer(null, false, 0);
        if (e != null) {
            return e;
        }
        // 返回元素为 null 表示线程被中断,则清除中断标识并抛出  InterruptedException 异常。
        Thread.interrupted();
        throw new InterruptedException();
    }
  • 如果队列头节点为一个数据节点,则尝试移除并返回队列头部的数据元素,否则返回 null
    /**
     *  尝试移除并返回栈顶的数据元素,如果栈顶节点为一个数据节点,否则返回 null
     */
    @Override
    public E poll() {
        return transferer.transfer(null, true, 0);
    }
  • 尝试移除并返回队列头部数据元素,如果不存在,则在指定的超时时间内阻塞等待其他线程插入数据,超时则返回 null。
    /**
     *  尝试移除并返回队列头部数据元素,如果不存在,则在指定的超时时间内阻塞等待其他线程插入数据。
     *  超时则返回 null。
     */
    @Override
    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        final E e = transferer.transfer(null, true, unit.toNanos(timeout));
        if (e != null || !Thread.interrupted()) {
            return e;
        }
        throw new InterruptedException();
    }

猜你喜欢

转载自www.cnblogs.com/zhuxudong/p/10087189.html