Java JUC包源码分析 - LinkedBlockingDueue

LinkedBlockingDueue是基于一个双向的链表,可以先进先出(队列),也可以先进后出 (栈)

不允许插入null,基本原理和方法都和LinkedBlockingQueue差不多

public class LinkedBlockingDeque<E>
    extends AbstractQueue<E>
    implements BlockingDeque<E>, java.io.Serializable {
    // node节点
    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;
        }
    }

    // 头尾两个节点并没有显式的链接,而且约定链接?

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    // 队列第一个节点,一种情况是头尾节点都是null的时候,另一种是头节点的有值但上一个prev是null
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    // 队列尾节点,一种情况是头尾节点都是null的时候,另一种要不就是尾节点有值但下一个next是null
    transient Node<E> last;

    // 队列元素个数
    private transient int count;

    // 队列最大容量
    private final int capacity;

    // 独占锁
    /** Main lock guarding all access */
    final ReentrantLock lock = new ReentrantLock();

    /** Condition for waiting takes */
    private final Condition notEmpty = lock.newCondition();

    /** Condition for waiting puts */
    private final Condition notFull = lock.newCondition();

    // 默认容量Integer.MAX_VALUE
    public LinkedBlockingDeque() {
        this(Integer.MAX_VALUE);
    }

    // 插入一个元素到队列尾部
    public boolean offer(E e) {
        return offerLast(e);
    }

    // 插入一个元素到队列尾部
    public boolean offerLast(E e) {
        if (e == null) throw new NullPointerException();
        // 新建节点
        Node<E> node = new Node<E>(e);
        final ReentrantLock lock = this.lock;
        // 加锁
        lock.lock();
        try {
            return linkLast(node);
        } finally {
            lock.unlock();
        }
    }

    // 把节点链接到尾节点的next
    private boolean linkLast(Node<E> node) {
        // assert lock.isHeldByCurrentThread();
        // 如果元素个数达到容量上限就返回false
        if (count >= capacity)
            return false;
        // 把node的前一个指针指向原来的last
        Node<E> l = last;
        node.prev = l;
        // 把插入的node置为新的last节点
        last = node;
        // 把原来的last节点的next指向node,也就是新的last
        // 如果头指针为null,则把尾指针赋值给头指针
        if (first == null)
            first = node;
        else
            l.next = node;
        // 把元素个数+1
        ++count;
        // 唤醒正在取元素的线程
        notEmpty.signal();
        return true;
    }

    // 取一个元素,头节点
    public E poll() {
        return pollFirst();
    }

    // 取队列头节点
    public E pollFirst() {
        final ReentrantLock lock = this.lock;
        // 加锁
        lock.lock();
        try {
            return unlinkFirst();
        } finally {
            lock.unlock();
        }
    }

    // 取走头节点并删除
    private E unlinkFirst() {
        // assert lock.isHeldByCurrentThread();
        Node<E> f = first;
        if (f == null)
            return null;
        // 保存头节点的下一个节点next
        Node<E> n = f.next;
        // 保存头节点的值
        E item = f.item;
        // 释放头节点的值,以及自己指向自己断除引用
        f.item = null;
        f.next = f; // help GC
        // 把头节点的下一个节点当作新的头节点
        first = n;
        // 如果那个节点是null,那就把尾节点也置null
        // 否则把头节点的前一个节点置null
        if (n == null)
            last = null;
        else
            n.prev = null;
        // 元素个数-1
        --count;
        // 唤醒正在插入元素的线程
        notFull.signal();
        return item;
    }
    
    // 放入一个元素到尾部,如果队列满就阻塞等待
    public void put(E e) throws InterruptedException {
        putLast(e);
    }
    public void putLast(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        Node<E> node = new Node<E>(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            while (!linkLast(node))
                notFull.await();
        } finally {
            lock.unlock();
        }
    }

    // 从头部获取一个元素并删除,如果队列为空就阻塞并等待
    public E take() throws InterruptedException {
        return takeFirst();
    }
    public E takeFirst() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E x;
            while ( (x = unlinkFirst()) == null)
                notEmpty.await();
            return x;
        } finally {
            lock.unlock();
        }
    }


    // 还有当作栈用的两个方法
    public void push(E e) {
        addFirst(e);
    }
    public E pop() {
        return removeFirst();
    }

    public void addFirst(E e) {
        if (!offerFirst(e))
            throw new IllegalStateException("Deque full");
    }
    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();
        }
    }
    private boolean linkFirst(Node<E> node) {
        // assert lock.isHeldByCurrentThread();
        // 如果达到容量了就马上返回
        if (count >= capacity)
            return false;
        // 获取头节点
        Node<E> f = first;
        // 新插入的节点的下一个节点指向头节
        node.next = f;
        // 把新插入的节点置为头节点
        first = node;
        // 把原头节点的前一个节点prev指向新插入的node
        if (last == null)
            last = node;
        else
            f.prev = node;
        // 元素个数+1
        ++count;
        // 唤醒正在取元素的线程
        notEmpty.signal();
        return true;
    }
    // 移除头节点
    public E removeFirst() {
        E x = pollFirst();
        if (x == null) throw new NoSuchElementException();
        return x;
    }
    public E pollFirst() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return unlinkFirst();
        } finally {
            lock.unlock();
        }
    }
    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;
        f.next = f; // help GC
        first = n;
        if (n == null)
            last = null;
        else
            n.prev = null;
        --count;
        notFull.signal();
        return item;
    }

}

 

    原文作者:JUC
    原文地址: https://blog.csdn.net/qq_24219459/article/details/82730196
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞