SynchronousQueue 1.8 source code parsing

[TOC]

SynchronousQueue 1.8 source code parsing

I. Introduction

SynchronousQueue is a very strange queue, feeling not call queue, because no internal data storage space, the queue can not peek, because the element does not exist, the thread will block any queued until a thread to the team, which is the queue is a set of operations enqueue and dequeue leaving together, the team is the same, must wait enqueue, must go hand in hand; queues for fair and unfair mode (refer to the queues matching threads), fair mode the data structure is a queue (FIFO), non-fair mode is used in a stack (LIFO).

Two, UML diagram

SynchronousQueue 1.8 source code parsing

Third, the basic member

abstract static class Transferer<E> {
    // 出队入队都是这一个方法
    abstract E transfer(E e, boolean timed, long nanos);
}

    // npu数
    static final int NCPUS = Runtime.getRuntime().availableProcessors();

    // 带超时时间的自旋次数
    static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;

    // 没有超时的自旋次数
    static final int maxUntimedSpins = maxTimedSpins * 16;
Unfair implementation TransferStack, key members

TransferStack inherited Transferer

Note: these states is important because inherited Transferer, so the transfer method from the team and the team are used, the state is used to distinguish and Methods section will explain later

        /** 0表示消费者 */
        static final int REQUEST    = 0;
        /** 1表示数据的生产者 */
        static final int DATA       = 1;
        /** 2 表示数据正在匹配 */
        static final int FULFILLING = 2;

        static final class SNode {
            volatile SNode next;        // 下一个节点
            volatile SNode match;       // 匹配的节点
            volatile Thread waiter;     // 等待的线程
            Object item;                // 数据
            int mode;                   // 模式 0 , 1 , 2
        }
    /** 头结点 */
    volatile SNode head;
TransferQueue fair implementation, key members

TransferQueue inherited Transferer

    static final class QNode {
            volatile QNode next;          // next 节点
            volatile Object item;         // 数据项
            volatile Thread waiter;       // 等待线程
            final boolean isData;         // 区分生产和消费
    }

        /** 头结点 */
        transient volatile QNode head;
        /** 尾节点 */
        transient volatile QNode tail;

Fourth, the common method

Construction method
    public SynchronousQueue() {
        this(false);
    }

    // 构造方法,fair表示公平或者非公平
    public SynchronousQueue(boolean fair) {
        transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
    }
TransferStack unfair common method
offer methods
    public boolean offer(E e) {
        // e 不能为null
        if (e == null) throw new NullPointerException();
        return transferer.transfer(e, true, 0) != null;
    }

    public boolean offer(E e, long timeout, TimeUnit unit)
            throws InterruptedException {
            // e 不能为null
        if (e == null) throw new NullPointerException();
        if (transferer.transfer(e, true, unit.toNanos(timeout)) != null)
            return true;
        if (!Thread.interrupted())
            return false;
        throw new InterruptedException();
    }
put method
public void put(E e) throws InterruptedException {
    // e 不能为null
        if (e == null) throw new NullPointerException();
        if (transferer.transfer(e, false, 0) == null) {
            // 支持中断
            Thread.interrupted();
            throw new InterruptedException();

    }
poll method
    public E poll() {
        return transferer.transfer(null, true, 0);
    }
take way
public E take() throws InterruptedException {
        E e = transferer.transfer(null, false, 0);
        if (e != null)
            return e;
        Thread.interrupted();
        throw new InterruptedException();
    }
transfer method
    E transfer(E e, boolean timed, long nanos) {

            SNode s = null; // constructed/reused as needed
            //  根据所传元素判断为生产or消费
            int mode = (e == null) ? REQUEST : DATA;

            for (;;) { // 无限循环
                SNode h = head; // 获取头结点
                if (h == null || h.mode == mode) {  // 头结点为空或者当前节点状态(0,1,2)和头结点相同
                    if (timed && nanos <= 0) {      // can't wait 设置有时间
                        // 节点不为null并且为取消状态
                        if (h != null && h.isCancelled())
                            // 弹出取消的节点
                            casHead(h, h.next);     // pop cancelled node
                        else
                            // 超时直接返回null
                            return null;
                     // 没有设置超时
                    } else if (casHead(h, s = snode(s, e, h, mode))) { // 将h设为自己的next节点
                        // 空旋或者阻塞直到s结点被FulFill操作所匹配
                        SNode m = awaitFulfill(s, timed, nanos);
                        if (m == s) {                // wait was cancelled 节点被取消了
                            clean(s);
                            return null;
                        }
                        // 找到匹配的线程了
                        // h == head 可能已经已经被匹配
                        // h.next 等于s 不同类型
                        if ((h = head) != null && h.next == s)
                            // 弹出h 和 s
                            casHead(h, s.next);     // help s's fulfiller
                        return (E) ((mode == REQUEST) ? m.item : s.item);
                    }
                // 未匹配
                } else if (!isFulfilling(h.mode)) { // try to fulfill // 尝试匹配节点
                    if (h.isCancelled())            // already cancelled // 节点被取消
                        casHead(h, h.next);         // pop and retry // 修改头结点
                    else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
                        for (;;) { // loop until matched or waiters disappear
                            SNode m = s.next;       // m is s's match
                            // 没有下一个节点了,结束这次循环,走最外层循环重新开始
                            if (m == null) {        // all waiters are gone // m等于null
                                casHead(s, null);   // pop fulfill node // cas 设置head
                                s = null;           // use new node next time
                                break;              // restart main loop // 结束循环
                            }
                            SNode mn = m.next;
                            if (m.tryMatch(s)) {     // 尝试匹配,成功
                                casHead(s, mn);     // pop both s and m
                                return (E) ((mode == REQUEST) ? m.item : s.item);
                            } else                  // lost match // 失败,说明m背的线程匹配了,或者取消了
                                s.casNext(m, mn);   // help unlink //  修改next节点
                        }
                    }
                } else {                            // help a fulfiller 正在匹配
                    SNode m = h.next;               // m is h's match
                    if (m == null)                  // waiter is gone 匹配完成了
                        casHead(h, null);           // pop fulfilling node
                    else {
                        SNode mn = m.next;
                        if (m.tryMatch(h))          // help match
                            casHead(h, mn);         // pop both h and m
                        else                        // lost match
                            h.casNext(m, mn);       // help unlink
                    }
                }
            }
        }
awaitFulfill 方法
    SNode awaitFulfill(SNode s, boolean timed, long nanos) {

            // 计算时间
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            // 获取当前线程
            Thread w = Thread.currentThread();
            // shouldSpin控制自旋
            // shouldSpin 用于检测当前节点是否需要自旋
            // 如果栈为空、该节点是首节点或者该节点是匹配节点,则先采用自旋,否则阻塞
            int spins = (shouldSpin(s) ?
                    (timed ? maxTimedSpins : maxUntimedSpins) : 0);
            for (;;) { // 死循环
                if (w.isInterrupted()) // 线程被中断
                    s.tryCancel();
                SNode m = s.match;
                if (m != null)  // 存在匹配节点 ,返回
                    return m;
                if (timed) { // 存在超时设置
                    nanos = deadline - System.nanoTime();
                    if (nanos <= 0L) {
                        s.tryCancel();
                        continue;
                    }
                }
                // 自旋;每次自旋的时候都需要检查自身是否满足自旋条件,满足就 - 1,否则为0
                if (spins > 0)
                    spins = shouldSpin(s) ? (spins-1) : 0;
                // 设置node的线程
                else if (s.waiter == null)
                    s.waiter = w; // establish waiter so can park next iter
                // 如果不是超时,就阻塞
                else if (!timed)
                    LockSupport.park(this);
                // 设置超时阻塞
                else if (nanos > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanos);
            }
        }
clean method
    void clean(SNode s) {
            s.item = null;   // forget item
            s.waiter = null; // forget thread

            // next节点
            SNode past = s.next;
            // next节点也被中断了,直接删除
            if (past != null && past.isCancelled())
                past = past.next;

            // Absorb cancelled nodes at head
            // 从栈顶开始找,清除取消的节点
            SNode p;
            while ((p = head) != null && p != past && p.isCancelled())
                casHead(p, p.next);

            // Unsplice embedded nodes
            // 从有效的头节点开始p ,到s的后继节点,继续清除
            while (p != null && p != past) {
                SNode n = p.next;
                if (n != null && n.isCancelled())
                    p.casNext(n, n.next);
                else
                    p = n;
            }
        }

Analysis of transfer methods:

  • We found that transfer can be judged by e empty or poll method is the offer method, which is to distinguish between those in and out of the team's.

  • The first case, if the queue is empty head, or head node queue exists and their mode of the same, there is first determined cancel out or, on the implementation of these operations have not enqueue operation is executed, and the newly added node Join top of the stack, then call awaitFulfill method blocks the thread until it is interrupted, time-out or the match is successful, why clog up because we can not match the patterns are the same, we can only block the thread until a thread different modes of matches, wake own, this is the end of the process awaitFulfill methods.

  • The second case, if the different modes of the team, is determined by the head node there isFulfilling matching method, not to perform the matching process,

    First, determine whether the node is canceled, there is no judgment in that he is not the only one node, if the cycle is to re-start the process, if not above these circumstances, you can begin to match the node, call tryMatch method successfully wake another node then along the stack, returns the result, failed to advance backwards, the next to find a node, there may be other threads competitive match.

  • The third case, different patterns into the team, but the head node is matched, it would help it to complete the match, and then re-take the whole cycle.
TransferQueue common equity method

The team and the team is the same way, we look at the main bar transfer method.

transfer method
    E transfer(E e, boolean timed, long nanos) {

            QNode s = null; // constructed/reused as needed
            // 判断是生产者 还是消费者
            boolean isData = (e != null);

            for (;;) {
                QNode t = tail;
                QNode h = head;
                // 没有初始化
                if (t == null || h == null)         // saw uninitialized value
                    continue;                       // spin
                // h==t 刚刚初始化 t.isData == isData,尾节点和当前节点的类型一样
                if (h == t || t.isData == isData) { // empty or same-mode
                    QNode tn = t.next; // 获取尾节点
                    if (t != tail)      // 尾节点发生变了变化             // inconsistent read
                        continue;
                    if (tn != null) {   // 重设为节点             // lagging tail
                        advanceTail(t, tn);
                        continue;
                    }
                    if (timed && nanos <= 0)  // 超时了       // can't wait
                        return null;
                    if (s == null) // 构建新节点
                        s = new QNode(e, isData);
                    if (!t.casNext(null, s))       // failed to link in 有竞争
                        continue;

                    // 替换尾节点
                    advanceTail(t, s);              // swing tail and wait
                    // 自旋/阻塞 返回的是中断取消/匹配的节点
                    Object x = awaitFulfill(s, e, timed, nanos);
                    // 中断
                    if (x == s) {                   // wait was cancelled
                        clean(t, s);
                        return null;
                    }

                    // 匹配成功了,需要执行出队操作
                    if (!s.isOffList()) {
                        // not already unlinked
                        // 修改头结点
                        advanceHead(t, s);          // unlink if head
                        if (x != null)              // and forget fields
                            s.item = s;
                        s.waiter = null;
                    }
                    return (x != null) ? (E)x : e;

                } else {                            // complementary-mode
                    // 出队从头元素开始
                    QNode m = h.next;               // node to fulfill
                    if (t != tail || m == null || h != head) // 队列发生变化重来
                        continue;                   // inconsistent read

                    Object x = m.item;
                    // isData == (x != null) 判断模式是否相同,不相同才能匹配
                    // x == m 说明已经被中断或者超时了
                    // m.casItem(x, e) 匹配
                    if (isData == (x != null) ||    // m already fulfilled
                            x == m ||                   // m cancelled
                            !m.casItem(x, e)) {// lost CAS
                        advanceHead(h, m);          // dequeue and retry
                        continue;
                    }
                    // 匹配成功
                    // 替换头
                    advanceHead(h, m);              // successfully fulfilled
                    // 唤醒等待线程
                    LockSupport.unpark(m.waiter); // 唤醒线程
                    return (x != null) ? (E)x : e;
                }
            }
        }

Analysis of transfer methods:

  • E is also judged by the enqueue or dequeue, all call transfer method, transfer method can be seen in two parts, enqueue and matching.
  • A first portion of the team, the team model is the same enqueuing starting from the tail node, obtaining the end node, determining the end node has not changed, there may be multi-threaded, the change to re-iterate, no determines tail node has no next node, it shows there is another thread adding new nodes, tail nodes need to be updated, and then construct a new node to join the current next node end node, update the tail node, then call awaitFulfill blocking the current node until the break, out or match, and then clear a successful match node, call the clean method.
  • The second part of the match (the team), the team is to start from scratch node, and then determine whether different mode, if canceled, cas setting item, in fact, is the transfer of data, if the match is successful, Wake m waiting threads, where attention set to become the head node m, in fact, the m node pop up, because we get the first match next node node.

V. Summary

SynchronousQueue implementation is very complex, we can see that although a blocking queue, but do not use locks; the queue for delivery scenario, there is no queue queue storage elements, the team and the team must go hand in hand.

Reference "Art Java concurrent programming."

Guess you like

Origin blog.51cto.com/14220760/2416470