概述
只在队列头部插入和删除元素的双向阻塞队列。该队列基于双向链表实现,双向链表仅使用一个ReenterantLock进行锁保护,并使用2个Condition来管理阻塞。因为只使用一个ReenterantLock,所以时间上,元素的插入和删除不能同时进行;空间上,元素的插入和删除只在队列的头部进行操作。
为了实现弱一致性的iterator,看起来我们需要保证每个节点都能通过它的前继节点实现gc可达性要求,但是这样会造成2个问题:
允许恶意的iterator无限制地占用内存。
。。
成员变量
/**
* 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;
双向链表的Node节点
/** 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
*/
//prev等于当前节点,表示前继节点是尾节点
Node<E> prev;
/**
* One of:
* - the real successor Node
* - this Node, meaning the successor is head
* - null, meaning there is no successor
*/
//next等于当前节点,表示后继节点是头节点
Node<E> next;
Node(E x) {
item = x;
}
}
putFirst()方法
将元素封装成Node节点,在Lock保护下,将Node节点链接到双向链表,插入到链表的头部,时间复杂度O(1)。如果链接失败,说明notFull Condition已经不满足,需要进行条件阻塞。
/**
* @throws NullPointerException {@inheritDoc}
* @throws InterruptedException {@inheritDoc}
*/
public void putFirst(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 (!linkFirst(node))
notFull.await();
} finally {
lock.unlock();
}
}
takeFirst()方法
在lock保护下,从双向链表的头部取出头节点。如果取出失败,说明notEmpty condition不满足,需要进行条件阻塞。
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();
}
}
linkFirst()方法
// Basic linking and unlinking operations, called only while holding lock
/**
* Links node as first element, or returns false if full.
*/
private boolean linkFirst(Node<E> node) {
// assert lock.isHeldByCurrentThread();
if (count >= capacity)
return false;
//获取双向链表的头节点
Node<E> f = first;
//设置待入队节点的next指针为原头节点
node.next = f;
//重置头节点为新入队的节点
first = node;
//如果last节点为null,设置last节点为该节点
if (last == null)
last = node;
else
//设置原头节点的prev指针为新的头节点
f.prev = node;
++count;
//唤醒阻塞在notEmpty条件上的线程
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;
//获取原头节点的后继节点n
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条件上的线程
notFull.signal();
return item;
}
备注:Deque 双端队列