LinkedBlockingDeque是一种支持双向并发的阻塞队列。
LinkedBlockingDeque特性
1.底层数据结构双向链表。
2.同时支持FIFO和FILO,从队列的头和尾同时操作(插入/删除)。
3.线程安全,使用重入锁ReentrantLock和两个Condition来控制并发。
4.容量可选(防止过度膨胀),即可以指定队列的容量。如果不指定,默认容量大小等于Integer.MAX_VALUE。
LinkedBlockingDeque属性
transient Node<E> first; // 头结点
transient Node<E> last; // 尾结点
private transient int count; // 当前队列节点数
private final int capacity; // 队列最大支持容量
final ReentrantLock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition();
private final Condition notFull = lock.newCondition();
// 节点数据结构
static final class Node<E> {
E item;
Node<E> prev;
Node<E> next;
Node(E x) {
item = x;
}
}
添加头尾结点
// 头部添加结点
private boolean linkFirst(Node<E> node) {
if (count >= capacity)
return false;
Node<E> f = first;
node.next = f;
first = node;
if (last == null) // 队列只有一个结点
last = node; // 头尾结点都指向node
else
f.prev = node;
++count;
notEmpty.signal(); // 唤醒take阻塞线程
return true;
}
// 尾部添加结点
private boolean linkLast(Node<E> node) {
if (count >= capacity)
return false;
Node<E> l = last;
node.prev = l;
last = node;
if (first == null) // 队列只有一个结点
first = node; // 头尾结点都指向node
else
l.next = node;
++count;
notEmpty.signal();
return true;
}
移除结点
unlinkFirst、unlinkLast移除头尾结点,unlink(Node<E> x)移除指定结点
void unlink(Node<E> x) {
Node<E> p = x.prev;
Node<E> n = x.next; // 先拿到结点x的前后结点
if (p == null) { // 前缀结点为空,说明x是头节点
unlinkFirst();
} else if (n == null) { // 后继结点为空,说明是尾结点
unlinkLast();
} else { // p,n相互指向
p.next = n;
n.prev = p;
x.item = null;
--count;
notFull.signal();
}
}
addFirst(E e)、addLast(E e)分别调用offerFirst(E e)、offerLast(E e),失败会抛出异常!
offerFirst(E e)、offerLast(E e)不能添加null,加锁分别调用linkFirst(Node<E> node)、linkLast(Node<E> node)。
putFirst(E e)、putLast(E e)也不能添加null,分别调用linkFirst(Node<E> node)、linkLast(Node<E> node),添加失败则阻塞。
offerFirst(E e, long timeout, TimeUnit unit)throws InterruptedException
offerLast(E e, long timeout, TimeUnit unit)throws InterruptedException这两个方法会响应中断,不能添加null,在超时时间内会阻塞指定时间,超时后返回false。
LinkedTransferDeque的节点遍历-迭代器iterator
LinkedBlockingDeque支持正向和逆向的两种迭代器,分别是方法Iterator、DescendingIterator。
Iterator和DescendingIterator都继承了AbstractItr内部抽象类,仅仅实现了AbstractItr的以下两个抽象方法firstNode()和nextNode(Node<E> n)。
还有一个可拆分迭代器LBDSpliterator<E>实现implements Spliterator<E>。
抽象类AbstractItr属性与方法
Node<E> next; // 迭代器实例创建时候拿到的第一个节点
E nextItem; // 迭代器实例创建时候拿到的第一个节点的内容
private Node<E> lastRet; // 上一次调用next()返回的节点,用于remove方法
abstract Node<E> firstNode();
abstract Node<E> nextNode(Node<E> n);
介绍几个AbstractItr的核心方法
/**
* 返回给定非空节点的后续节点,但可能已被删除。
*/
private Node<E> succ(Node<E> n) {
for (;;) {
Node<E> s = nextNode(n);
if (s == null) // 队列没有更多元素了,空或者到头了
return null;
else if (s.item != null) // 有效节点
return s;
else if (s == n) // 自链接表示是正常的从队列头或者尾出队,直接取最近的头或尾节点即可
return firstNode();
else
n = s; // s.item ==null表示s是被移除的内部节点,遍历下一个
}
}
/**
* 推进节点
*/
void advance() {
final ReentrantLock lock = LinkedBlockingDeque.this.lock;
lock.lock();
try {
// assert next != null;
next = succ(next);
nextItem = (next == null) ? null : next.item;
} finally {
lock.unlock();
}
}
public boolean hasNext() {
return next != null;
}
public E next() {
if (next == null)
throw new NoSuchElementException();
lastRet = next; // 保留上一次返回的next节点
E x = nextItem;
advance();
return x;
}
public void remove() {
Node<E> n = lastRet;//remove移除的是上一次调用next方法获取的next节点
if (n == null)
throw new IllegalStateException();
lastRet = null;
final ReentrantLock lock = LinkedBlockingDeque.this.lock;
lock.lock();
try {
if (n.item != null)
unlink(n);
} finally {
lock.unlock();
}
}