1. 程式人生 > >LinkedBlockingDeque原始碼講解

LinkedBlockingDeque原始碼講解

尊重原創,轉載請標明出處   http://blog.csdn.net/abcdef314159

原始碼:\sources\Android-25

LinkedBlockingDeque是雙向連結串列阻塞佇列,他維護的是個連結串列節點Node,和前面的分析的PriorityBlockingQueue有一點區別,PriorityBlockingQueue維護的是個陣列。他和LinkedList很相似,不過LinkedList沒有指定容量,LinkedBlockingDeque是有容量大小的,大小為apacity,如果沒有指定apacity,那麼最大空間為Integer.MAX_VALUE.下面看一下LinkedBlockingDeque的主要方法。
    /** Doubly-linked list node class */
    static final class Node<E> {
        /**
         * The item, or null if this node has been removed.
         */
        E item;

        /**
         * One of:
         * - the real predecessor Node
         * - this Node, meaning the predecessor is tail
         * - null, meaning there is no predecessor
         */
        Node<E> prev;

        /**
         * One of:
         * - the real successor Node
         * - this Node, meaning the successor is head
         * - null, meaning there is no successor
         */
        Node<E> next;

        Node(E x) {
            item = x;
        }
    }
Node就是LinkedBlockingDeque維護的連結串列節點,這個節點有個前一個prev和後一個next,所以他維護的連結串列是雙向的。當然他還有兩個變數,一個是指向第一個,一個是指向最後一個
    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;
LinkedBlockingDeque的構造方法比較多,下面隨便看其中的一個。
    /**
     * Creates a {@code LinkedBlockingDeque} with a capacity of
     * {@link Integer#MAX_VALUE}, initially containing the elements of
     * the given collection, added in traversal order of the
     * collection's iterator.
     *
     * @param c the collection of elements to initially contain
     * @throws NullPointerException if the specified collection or any
     *         of its elements are null
     */
    public LinkedBlockingDeque(Collection<? extends E> c) {
        this(Integer.MAX_VALUE);
        final ReentrantLock lock = this.lock;
        lock.lock(); // Never contended, but necessary for visibility
        try {
            for (E e : c) {
                if (e == null)
                    throw new NullPointerException();
                if (!linkLast(new Node<E>(e)))//不停的新增到隊尾,如果空間滿就會丟擲異常
                    throw new IllegalStateException("Deque full");
            }
        } finally {
            lock.unlock();
        }
    }
下面來看一下linkFirst方法
    /**
     * Links node as first element, or returns false if full.
     */
    private boolean linkFirst(Node<E> node) {
		//新增到第一個節點的前面
        // assert lock.isHeldByCurrentThread();
		//如果已經滿了,就直接返回false。
        if (count >= capacity)
            return false;
        Node<E> f = first;
		//讓原來的頭結點成為新節點的下一個節點。
        node.next = f;
		//讓新節點成為first節點
        first = node;
		//如果last為null,說明原來連結串列是為null的,也讓尾節點指向新節點
        if (last == null)
            last = node;
        else
		//node已經是連結串列的頭結點了,讓node等於f的前一個節點,因為連結串列是雙向的。
		//為什麼last等於null的時候不執行這段程式碼,是因為last等於null的時候表示
		//沒有節點的,新增的時候就一個節點。
            f.prev = node;
        ++count;//連結串列數量加1
        notEmpty.signal();
        return true;
    }
接著再看下一個方法linkLast
    /**
     * Links node as last element, or returns false if full.
     */
    private boolean linkLast(Node<E> node) {
        // assert lock.isHeldByCurrentThread();
		// 新增到連結串列的尾,如果滿了,直接返回false
        if (count >= capacity)
            return false;
        Node<E> l = last;
		//既然是新增到尾節點,那麼之前尾節點就是新節點的前一個節點。
        node.prev = l;
		//然後讓last指向新節點
        last = node;
        if (first == null)
		//如果原來節點為空,同時也讓新節點成為首節點。
            first = node;
        else
		//因為是雙向連結串列,所以這裡讓新節點成為原來尾節點的下一個節點
            l.next = node;
        ++count;//連結串列數量加1
        notEmpty.signal();
        return true;
    }
再看下一個方法unlinkFirst,斷開首節點
    /**
     * Removes and returns first element, or null if empty.
     */
    private E unlinkFirst() {
		//移除第一個節點。
        // assert lock.isHeldByCurrentThread();
        Node<E> f = first;
        if (f == null)
            return null;
			//儲存首節點的下一個節點
        Node<E> n = f.next;
        E item = f.item;
        f.item = null;
		//讓首節點成為首節點的下一個節點的,就是自己的下一個指向自己,因為是first節點,
		//首節點的前一個為空,所以這裡其實就是讓首節點與連結串列斷開了
        f.next = f; // help GC
		//讓first節點指向first的下一個節點。
        first = n;
        if (n == null)
            last = null;
        else
		//既然n是首節點了,那麼他的前一個肯定要為null的
            n.prev = null;
        --count;//數量減1
        notFull.signal();
        return item;
    }
接著是unlinkLast方法,表示斷開最後一個節點
    /**
     * Removes and returns last element, or null if empty.
     */
    private E unlinkLast() {
        // assert lock.isHeldByCurrentThread();
        Node<E> l = last;
		//如果為空,直接返回
        if (l == null)
            return null;
			//儲存最後一個節點的前一個節點
        Node<E> p = l.prev;
        E item = l.item;
        l.item = null;
		//讓最後一個節點的前一個指向自己,相當於最後一個節點與
		//連結串列斷開。
        l.prev = l; // help GC
		//然後讓last指向之前最後一個連結串列的前一個
        last = p;
		//如果等於null,相當於連結串列直接刪除。
        if (p == null)
            first = null;
        else
		//否則讓最後一個連結串列的下一個指向null
            p.next = null;
        --count;//數量減1
        notFull.signal();
        return item;
    }
繼續看,下面一個是unlink方法
    /**
     * Unlinks x.
     */
    void unlink(Node<E> x) {
        // assert lock.isHeldByCurrentThread();
		//儲存當前節點的前一個和後一個
        Node<E> p = x.prev;
        Node<E> n = x.next;
        if (p == null) {
			//如果前一個等於null,說明x是first節點,直接刪除first節點即可
            unlinkFirst();
        } else if (n == null) {
		//如果後一個等於null,說明x是尾節點,直接刪除last節點即可
            unlinkLast();
        } else {
		//連結串列的斷開其實很簡單,就是讓當前節點的下一個成為當前節點前一個的下一個,
		//當前節點的前一個成為當前節點下一個的前一個。
            p.next = n;
            n.prev = p;
            x.item = null;
            // Don't mess with x's links.  They may still be in use by
            // an iterator.
            --count;
            notFull.signal();
        }
    }
接著看offerFirst方法,其實程式碼很簡單
    /**
     * @throws NullPointerException {@inheritDoc}
     */
    public boolean offerFirst(E e) {
        if (e == null) throw new NullPointerException();
        Node<E> node = new Node<E>(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return linkFirst(node);//斷開首節點
        } finally {
            lock.unlock();
        }
    }

然後add,offe,put,remove,pollFirst,pollLast,takeFirst,takeLast,pollFirst,pollLast基本上都呼叫上面的方法,都很簡單,這裡就不在介紹。