Java JUC包源码分析 - ConcurrentLinkedQueue

ConcurrentLinkedQueue不同于LinkedBlockingQueue,它没有利用ReentranLock以及Condition条件。而是利用死循环+CAS来实现线程安全,也就是一个重试的机制。

ConcurrentLinkedQueue是一个无阻塞的高效的队列。

ConcurrentLinkedQueue是基于单向链表的。

public class ConcurrentLinkedQueue extends AbstractQueue
        implements Queue, java.io.Serializable {
    // 单向链表,对节点的操作都是基于Unsafe的原子操作
    private static class Node {
        volatile E item;
        volatile Node next;

        /**
         * Constructs a new node.  Uses relaxed write because item can
         * only be seen after publication via casNext.
         */
        Node(E item) {
            UNSAFE.putObject(this, itemOffset, item);
        }

        boolean casItem(E cmp, E val) {
            return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
        }

        void lazySetNext(Node val) {
            UNSAFE.putOrderedObject(this, nextOffset, val);
        }

        boolean casNext(Node cmp, Node val) {
            return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
        }

        // Unsafe mechanics

        private static final sun.misc.Unsafe UNSAFE;
        private static final long itemOffset;
        private static final long nextOffset;

        static {
            try {
                UNSAFE = sun.misc.Unsafe.getUnsafe();
                Class k = Node.class;
                itemOffset = UNSAFE.objectFieldOffset
                    (k.getDeclaredField("item"));
                nextOffset = UNSAFE.objectFieldOffset
                    (k.getDeclaredField("next"));
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    }

    /**
     * A node from which the first live (non-deleted) node (if any)
     * can be reached in O(1) time.
     * Invariants:
     * - all live nodes are reachable from head via succ()
     * - head != null
     * - (tmp = head).next != tmp || tmp != head
     * Non-invariants:
     * - head.item may or may not be null.
     * - it is permitted for tail to lag behind head, that is, for tail
     *   to not be reachable from head!
     */
    // 头节点
    private transient volatile Node head;

    /**
     * A node from which the last node on list (that is, the unique
     * node with node.next == null) can be reached in O(1) time.
     * Invariants:
     * - the last node is always reachable from tail via succ()
     * - tail != null
     * Non-invariants:
     * - tail.item may or may not be null.
     * - it is permitted for tail to lag behind head, that is, for tail
     *   to not be reachable from head!
     * - tail.next may or may not be self-pointing to tail.
     */
    // 尾节点
    private transient volatile Node tail;

    /**
     * Creates a {@code ConcurrentLinkedQueue} that is initially empty.
     */
    public ConcurrentLinkedQueue() {
        head = tail = new Node(null);
    }

    // 插入一个元素到尾节点
    public boolean offer(E e) {
        // 检查插入的元素非空
        checkNotNull(e);
        // 新建一个节点
        final Node newNode = new Node(e);
        
        // 死循环,尾节点给t,t给p
        for (Node t = tail, p = t;;) {
            // 取出p的下一个节点,在单线程下应该是null,多线程情况下,又没有加锁,所以就会有        
            // elseif或else的情况
            Node q = p.next;
            // 如果q=null,说明此刻p还是满足最后一个节点的条件
            if (q == null) {
                // p is last node
                // 原子的设置p的下一个节点为新节点newNode
                if (p.casNext(null, newNode)) {
                    // Successful CAS is the linearization point
                    // for e to become an element of this queue,
                    // and for newNode to become "live".
                    // 如果设置成功了,再次检查p还是不是尾节点,如果不是就设置尾节点为newNode
                    // 理论上说不是了,因为p的next已经不是null,但是要是newNode被gc了就不一定
                    if (p != t) // hop two nodes at a time
                        casTail(t, newNode);  // Failure is OK.
                    // 这里可以直接返回true是因为上面cas就算失败,其实也就是把null放到tail的 
                    // next,和原来一样
                    return true;
                }
                // Lost CAS race to another thread; re-read next
            }
            // 
            else if (p == q)
                // 此时,若尾节点没有发生变化的话,那么,应该是头节点发生了变化,则设置p为头节 
                // 点,然后重新遍历链表;否则(尾节点变化的话),则设置p为尾节点
                // We have fallen off list.  If tail is unchanged, it
                // will also be off-list, in which case we need to
                // jump to head, from which all live nodes are always
                // reachable.  Else the new tail is a better bet.
                p = (t != (t = tail)) ? t : head;
            else
                // 如果p和t相等,则设置p为q。否则的话,判断“尾节点是否发生变化”,没有变化的话, 
                // 则设置p为q;否则,设置p为尾节点。
                // Check for tail updates after two hops.
                p = (p != t && t != (t = tail)) ? t : q;
        }
    }

    // 取出头节点并删除
    public E poll() {
        // 打了一个lable
        restartFromHead:
        for (;;) {
            for (Node h = head, p = h, q;;) {
                E item = p.item;
                // 设置头节点的值为null
                if (item != null && p.casItem(item, null)) {
                    // Successful CAS is the linearization point
                    // for item to be removed from this queue.
                    // 如果p已经不是头节点了,就更新头节点为原来头节点的下一个节点
                    if (p != h) // hop two nodes at a time
                        updateHead(h, ((q = p.next) != null) ? q : p);
                    return item;
                }
                // 表头的下一个节点为null,即链表只有一个“内容为null的表头节点”。则更新表头
                // 为p,并返回null。
                else if ((q = p.next) == null) {
                    updateHead(h, p);
                    return null;
                }
                // 这可能到由于else的发生导致p=q,在该情况下跳转到restartFromHead标记重新操作
                else if (p == q)
                    continue restartFromHead;
                else
                    p = q;
            }
        }
    }

    /**
     * Tries to CAS head to p. If successful, repoint old head to itself
     * as sentinel for succ(), below.
     */
    final void updateHead(Node h, Node p) {
        if (h != p && casHead(h, p))
            h.lazySetNext(h);
    }


}

 

你可能感兴趣的:(Java源码分析,Java多线程)