比起ArrayBlockingQueue,LinkedBlockingQueue应该是最被大家常用的阻塞队列,LinkedBlockingQueue是基于链表的一种可选容量的阻塞队列,也就是说,在构造LinkedBlockingQueue实例的时候,你可以像ArrayBlockingQueue那样指定队列大小,也可以不指定大小(这时候默认就是Integer.MAX_VALUE),指定队列的大小是为了防止队列过度的扩张,导致内存被过度占用或溢出。链表的节点是在每一次插入时动态的创建的,除非这会导致队列超出容量限制。LinkedBlockingQueue的容量在实例被构造完成之后也是不允许被更改的。
与ArrayBlockingQueue一样LinkedBlockingQueue不允许插入null值,也是先进先出FIFO队列,队列的头部是队列中存在时间最长的元素,新元素被插入到队尾,队列出队从头部开始。与ArrayBlockingQueue相比,LinkedBlockingQueue通常具有更高的吞吐量,但在大多数并发应用程序中性能的可预测性较差。
LinkedBlockingQueue采用了“双锁队列” 算法,元素的入队和出队分别由putLock、takeLock两个独立的可重入锁来实现。所以比起ArrayBlockingQueue明显提高了吞吐量。
源码分析
先看看其成员变量:
1 static class Node<E> { 2 E item; 3 4 /** 5 * One of: 6 * - the real successor Node 7 * - this Node, meaning the successor is head.next 8 * - null, meaning there is no successor (this is the last node) 9 */ 10 Node<E> next; 11 12 Node(E x) { item = x; } 13 } 14 15 /** The capacity bound, or Integer.MAX_VALUE if none */ 16 private final int capacity; 17 18 /** Current number of elements */ 19 private final AtomicInteger count = new AtomicInteger(); 20 21 /** 22 * Head of linked list. 23 * Invariant: head.item == null 24 */ 25 transient Node<E> head; 26 27 /** 28 * Tail of linked list. 29 * Invariant: last.next == null 30 */ 31 private transient Node<E> last; 32 33 /** Lock held by take, poll, etc */ 34 private final ReentrantLock takeLock = new ReentrantLock(); 35 36 /** Wait queue for waiting takes */ 37 private final Condition notEmpty = takeLock.newCondition(); 38 39 /** Lock held by put, offer, etc */ 40 private final ReentrantLock putLock = new ReentrantLock(); 41 42 /** Wait queue for waiting puts */ 43 private final Condition notFull = putLock.newCondition();