LinkedBlockingQueue源码分析-初始化

166 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

LinkedBlockingQueue特点

LinkedBlockingQueue通常叫做链表阻塞队列,从命名可以知道,其底层数据是链表,且队列是可阻塞的。 LinkedBlockingQueue的特点:

  1. 基于链表实现的阻塞队列,底层的数据结构为链表
  2. 基于链表实现先入先出的队列,新元素放在队尾,从队头部获取元素
  3. 链表大小在初始化的时候可以设置大小,默认为 Integer 的最大值
  4. 可以使用Iterator 进行迭代

属性

源码:

public class LinkedBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
    private static final long serialVersionUID = -6903933977591709194L;
    
    /**
     * Linked list node class
     */
    static class Node<E> {
        E item;

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

        Node(E x) { item = x; }
    }
    
    
    /** The capacity bound, or Integer.MAX_VALUE if none */
    private final int capacity;

    /** Current number of elements */
    private final AtomicInteger count = new AtomicInteger();

    /**
     * Head of linked list.
     * Invariant: head.item == null
     */
    transient Node<E> head;

    /**
     * Tail of linked list.
     * Invariant: last.next == null
     */
    private transient Node<E> last;

    /** Lock held by take, poll, etc */
    private final ReentrantLock takeLock = new ReentrantLock();

    /** Wait queue for waiting takes */
    private final Condition notEmpty = takeLock.newCondition();

    /** Lock held by put, offer, etc */
    private final ReentrantLock putLock = new ReentrantLock();

    /** Wait queue for waiting puts */
    private final Condition notFull = putLock.newCondition();

    ......
}

static class Node<E> 表示链表的元素节点

Node<E> next; 表示当前元素指向的下一个节点,如果为null,则表示当前节点为最后一个节点

private final int capacity;链表的容量,默认 Integer.MAX_VALUE

private final AtomicInteger count = new AtomicInteger();链表已有元素大小,使用 AtomicInteger,所以是线程安全的

transient Node<E> head; 链表头

private transient Node<E> last;链表尾

private final ReentrantLock takeLock = new ReentrantLock(); take 时的锁

private final Condition notEmpty = takeLock.newCondition();take 的条件队列

private final ReentrantLock putLock = new ReentrantLock();put 时的锁

private final Condition notFull = putLock.newCondition();put 的条件队列

总结: 设计了两把锁,一个是take锁,一个是put锁,目的是为了让两个操作互相不干扰,同步进行

初始化

源码:

    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

    public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node<E>(null);
    }

    public LinkedBlockingQueue(Collection<? extends E> c) {
        this(Integer.MAX_VALUE);
        final ReentrantLock putLock = this.putLock;
        putLock.lock(); // Never contended, but necessary for visibility
        try {
            int n = 0;
            for (E e : c) {
                if (e == null)
                    throw new NullPointerException();
                if (n == capacity)
                    throw new IllegalStateException("Queue full");
                enqueue(new Node<E>(e));
                ++n;
            }
            count.set(n);
        } finally {
            putLock.unlock();
        }
    }

源码中提供了三种初始化的方式: 第一种:使用默认的 Integer 的最大值进行初始化 第二种:指定链表容量大小初始化 第三章:使用已有集合数据进行初始化