目录
7、iterator / descendingIterator
LinkedBlockingDeque表示一个可选固定容量的,线程安全的、基于链表和ReentrantLock实现的双端队列,即可以从队列头或者队列尾添加或者移除元素,本篇博客就详细探讨该类的实现。
1、定义
LinkedBlockingDeque的类继承关系如下:
BlockingDeque继承自BlockingQueue和Deque,包含的方法如下:
后面会详细介绍各方法的用途。该类包含的实例属性如下:
//第一个节点
transient Node<E> first;
//最后一个节点
transient Node<E> last;
//队列中包含的元素个数
private transient int count;
//队列的容量
private final int capacity;
//同步锁
final ReentrantLock lock = new ReentrantLock();
//如果队列是空的,则在此Condition上等待
private final Condition notEmpty = lock.newCondition();
//如果队列是满的,则在此Condition上等待
private final Condition notFull = lock.newCondition();
Node是一个静态内部类,表示队列中的一个节点,其定义如下:
prev和next就是该节点的前后节点了,用于构成一条双向链表。
2、构造方法
同LinkedBlockingQueue,容量是可选的,如果不指定容量,则容量默认是int的最大值
//无固定容量时,默认容量为int的最大值
public LinkedBlockingDeque() {
this(Integer.MAX_VALUE);
}
//固定容量
public LinkedBlockingDeque(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
}
public LinkedBlockingDeque(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
final ReentrantLock lock = this.lock;
lock.lock(); //加锁和解锁会保证修改对其他CPU可见
try {
for (E e : c) {
if (e == null)
throw new NullPointerException();
if (!linkLast(new Node<E>(e))) //容量达到上限,抛出异常
throw new IllegalStateException("Deque full");
}
} finally {
lock.unlock();
}
}
private boolean linkLast(Node<E> node) {
// assert lock.isHeldByCurrentThread();
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;
}
3、add / offer / put
add系列有三个,add,addLast和addFirst,add的实现就是addLast,三个方法都是插入一个元素,如果满了返回false,不等待,否则返回true,addLast是插入到链表末尾,addFirst是插入到链表头。addLast和addFirst的实现就是调用不带时间参数的对应offerLast和offerFirst方法。
put系列也有三个,put,putFirst和putLast,put的实现就是putLast;put类方法都是往链表中插入,如果队列满了则无期限等待直到被中断或者插入成功为止,其中putFirst是插入到链表头,putLast是插入到链表尾。
offer系列有6个,offer、offerFirst、offerLast,offer的实现就是offerLast,这三个方法每个都有一个可以指定等待时间的重载版本,不带时间参数的版本不会阻塞,如果满了返回false,否则插入成功返回true;带时间参数的版本会阻塞指定的时间,如果超时则返回false,如果被中断了则抛出异常,插入成功返回true,其中offerFirst插入到链表头,offerLast插入到链表尾。具体实现如下:
public boolean add(E e) {
addLast(e);
return true;
}
public void addFirst(E e) {
if (!offerFirst(e))
throw new IllegalStateException("Deque full");
}
public void addLast(E e) {
if (!offerLast(e))
throw new IllegalStateException("Deque full");
}
public boolean offer(E e) {
return offerLast(e);
}
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
return offerLast(e, timeout, unit);
}
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();
}
}
public boolean offerFirst(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (!linkFirst(node)) { //如果链表是满的则等待
if (nanos <= 0) //等待超时返回false
return false;
nanos = notFull.awaitNanos(nanos);
}
//插入成功返回true
return true;
} finally {
lock.unlock();
}
}
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();
}
}
public boolean offerLast(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (!linkLast(node)) { //链表满了,等待
if (nanos <= 0)
return false; //等待超时
nanos = notFull.awaitNanos(nanos);
}
return true;
} finally {
lock.unlock();
}
}
public void put(E e) throws InterruptedException {
putLast(e);
}
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();
}
}
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();
}
}
private boolean linkFirst(Node<E> node) {
// assert lock.isHeldByCurrentThread();
if (count >= capacity) //容量达到上限,返回false
return false;
Node<E> f = first;
node.next = f;
first = node;
if (last == null)
last = node; //链表未初始化,first和last指向同一个节点
else
f.prev = node; //插入到原first节点的前面
//队列元素个数加1
++count;
//唤醒因为队列是空的而阻塞的线程
notEmpty.signal();
return true;
}
4、poll / take / peek
peek方法同add方法相对,同样有三个,peek、peekFirst和peekLast,peek的实现就是peekFirst,peekFirst返回链表头的元素,peekLast返回链表尾的元素,如果链表为空则返回null,不需要等待,也不需要将链表头或者链表尾节点移除。
poll方法同offer方法相对,同样有六个,poll、pollFirst和pollLast,poll的实现是pollFirst,pollFirst移除链表头并返回链表头的元素,pollLast移除链表尾并返回链表尾的元素,如果链表为空则直接返回null,不需要等待;这三个方法都有一个带时间参数的重载版本,如果链表为空则必须要等待指定的时间,如果超时了返回null,如果等待期间被中断则抛出异常,如果链表不为空则移除链表头或者链表尾并返回关联的元素。
take方法同put方法相对,同样有三个,take、takeFirst和takeLast,take的实现就是takeFirst,takeFirst移除链表头并返回链表头的元素,takeLast移除链表尾并返回链表尾的元素,如果链表为空则无期限等待直到链表不为空成功获取链表头或者链表尾的元素为止,如果被中断则抛出异常。具体实现如下:
public E peek() {
return peekFirst();
}
public E peekFirst() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//如果链表为空返回null,否则返回first节点的元素
return (first == null) ? null : first.item;
} finally {
lock.unlock();
}
}
public E peekLast() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//如果链表为空返回null,否则返回last节点的元素
return (last == null) ? null : last.item;
} finally {
lock.unlock();
}
}
public E poll() {
return pollFirst();
}
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
return pollFirst(timeout, unit);
}
public E pollFirst() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//移除并返回链表头,如果链表为空则返回null
return unlinkFirst();
} finally {
lock.unlock();
}
}
public E pollFirst(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
E x;
while ( (x = unlinkFirst()) == null) { //链表为空则等待指定的时间
if (nanos <= 0)
return null; //等待超时返回null
nanos = notEmpty.awaitNanos(nanos);
}
return x;
} finally {
lock.unlock();
}
}
public E pollLast() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//移除并返回链表尾,如果链表为空则返回null
return unlinkLast();
} finally {
lock.unlock();
}
}
public E pollLast(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
E x;
while ( (x = unlinkLast()) == null) { //链表为空则等待指定的时间
if (nanos <= 0)
return null; //等待超时返回null
nanos = notEmpty.awaitNanos(nanos);
}
return x;
} 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 E takeLast() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
E x;
while ( (x = unlinkLast()) == null) //链表为空则无期限等待
notEmpty.await();
return x;
} finally {
lock.unlock();
}
}
private E unlinkFirst() {
// assert lock.isHeldByCurrentThread();
Node<E> f = first;
if (f == null) //链表为空,返回null
return null;
Node<E> n = f.next;//获取下一个节点
E item = f.item;
f.item = null;
f.next = f; //next指向自己,从链表中移除
first = n; //重置链表头
if (n == null)
last = null; //如果first就是最后一个元素了,将last也置为null,因为这两个最初都是指向同一个元素
else
n.prev = null; //将first的前一个元素置为null
//元素个数减1
--count;
//唤醒因为线程满的而阻塞的线程
notFull.signal();
return item;
}
private E unlinkLast() {
// assert lock.isHeldByCurrentThread();
Node<E> l = last;
if (l == null) //链表为空,返回null
return null;
Node<E> p = l.prev; //获取前一个节点
E item = l.item;
l.item = null;
l.prev = l; //prev指向自己,从链表中移除
last = p;
if (p == null)
first = null; //如果last就是最后一个元素了,将first也置为null
else
p.next = null;
//元素个数减1
--count;
//唤醒因为线程满的而阻塞的线程
notFull.signal();
return item;
}
5、remove / clear /drainTo
remove方法有两个重载版本,一个不带参数,调用removeFirst方法实现,removeFirst会移除链表头并返回关联的元素,调用pollFirst实现;与之对应的removeLast会移除链表尾并返回关联的元素,调用pollLast实现,这两个如果返回的元素为null会抛出异常。
remove的另一个带参数的版本可以指定需要移除的元素,调用removeFirstOccurrence方法实现,该方法会从链表头开始往后遍历直到找到与目标元素匹配的节点,将该节点从链表中移除,然后返回true,如果没有找到返回false;与removeFirstOccurrence对应的,有一个removeLastOccurrence方法,从链表尾开始往前遍历直到找到与目标元素匹配的节点,将该节点从链表中移除,然后返回true,如果没有找到返回false。
clear方法表示将链表中的节点都移除, drainTo方法表示将链表中的元素移除并放到指定的集合中,如果没有指定数量,则默认将链表中所有元素都移除,如果指定数量了,则移除指定数量的元素,直到链表为空为止。
public E remove() {
return removeFirst();
}
public E removeFirst() {
//移除链表头并返回关联的元素
E x = pollFirst();
if (x == null) throw new NoSuchElementException(); //链表为空抛出异常
return x;
}
public E removeLast() {
//移除链表尾并返回关联的元素
E x = pollLast();
if (x == null) throw new NoSuchElementException(); //链表为空抛出异常
return x;
}
public boolean remove(Object o) {
return removeFirstOccurrence(o);
}
public boolean removeFirstOccurrence(Object o) {
if (o == null) return false;
final ReentrantLock lock = this.lock;
lock.lock();
try {
//从链表头往后遍历
for (Node<E> p = first; p != null; p = p.next) {
if (o.equals(p.item)) { //找到目标节点将其从链表中移除,返回true
unlink(p);
return true;
}
}
return false; //没有找到返回false
} finally {
lock.unlock();
}
}
public boolean removeLastOccurrence(Object o) {
if (o == null) return false;
final ReentrantLock lock = this.lock;
lock.lock();
try {
//从链表尾往前遍历
for (Node<E> p = last; p != null; p = p.prev) {
if (o.equals(p.item)) {
unlink(p);
return true;
}
}
return false;
} finally {
lock.unlock();
}
}
public void clear() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//从链表头往后遍历,将所有元素从链表中移除
for (Node<E> f = first; f != null; ) {
f.item = null;
Node<E> n = f.next;
f.prev = null;
f.next = null;
f = n;
}
//first和last都置为null,元素个数置为0
first = last = null;
count = 0;
notFull.signalAll();
} finally {
lock.unlock();
}
}
public int drainTo(Collection<? super E> c) {
//将队列中的所有元素拷贝到c中
return drainTo(c, Integer.MAX_VALUE);
}
public int drainTo(Collection<? super E> c, int maxElements) {
//参数校验
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
return 0;
final ReentrantLock lock = this.lock;
lock.lock();
try {
//取两者的最小值
int n = Math.min(maxElements, count);
for (int i = 0; i < n; i++) {
//这里没有使用pollFirst是为了避免锁重入
//将first节点的元素添加到c中
c.add(first.item); // In this order, in case add() throws.
//移除链表头
unlinkFirst();
}
return n;
} finally {
lock.unlock();
}
}
6、push / pop
这两个用法用于实现先进后出的栈,这两方法都不会阻塞,其实现如下:
//push时都是插入到链表头
public void push(E e) {
addFirst(e);
}
//pop时都是从链表头移除元素,即后插入的元素会先出
public E pop() {
return removeFirst();
}
7、iterator / descendingIterator
iterator用于从链表头开始遍历,descendingIterator用于从链表尾开始遍历,其实现如下:
public Iterator<E> iterator() {
return new Itr();
}
public Iterator<E> descendingIterator() {
return new DescendingItr();
}
Itr和DescendingItr都是内部类,都继承自AbstractItr,其实现如下:
AbstractItr的实现如下:
private abstract class AbstractItr implements Iterator<E> {
//下一次next方法对应的节点
Node<E> next;
//下一次next方法关联的元素
E nextItem;
//上一次next方法返回的节点
private Node<E> lastRet;
abstract Node<E> firstNode();
abstract Node<E> nextNode(Node<E> n);
AbstractItr() {
// set to initial position
final ReentrantLock lock = LinkedBlockingDeque.this.lock;
lock.lock();
try {
//获取第一个节点
next = firstNode();
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;
E x = nextItem;
advance();
return x;
}
/**
* next方法调用此方法获取下一次返回的节点
*/
void advance() {
final ReentrantLock lock = LinkedBlockingDeque.this.lock;
lock.lock();
try {
//获取下一个遍历的元素
next = succ(next);
nextItem = (next == null) ? null : next.item;
} finally {
lock.unlock();
}
}
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)
//如果这个节点刚好从链表移除了,则从头开始遍历,正常不会出现此情形,因为advance和元素移除都是在锁下进行的
return firstNode();
else
n = s;
}
}
public void remove() {
Node<E> n = lastRet;
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();
}
}
}