回顾上一篇中,我们讲述了基于数组实现的ArrayBlockingQueue,这一篇我们将学习另一种基于链表实现的LinkedBlockingQueue。
首先看看LinkedBlockingQueue一些重要属性
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
static class Node<E> { //节点类,元素以节点的形式存在
E item; //节点中实际数据
Node<E> next; // 后继节点
Node(E x) { item = x; }
}
// 队列容量,默认Integer的最大值
private final int capacity;
// 当前队列中的元素个数
private final AtomicInteger count = new AtomicInteger();
// 队列头节点
transient Node<E> head;
// 队列尾节点
private transient Node<E> last;
// 取元素需要takeLock锁
private final ReentrantLock takeLock = new ReentrantLock();
// 队列为空时,取元素操作将阻塞在此条件上
private final Condition notEmpty = takeLock.newCondition();
// 添加元素需要putLock锁
private final ReentrantLock putLock = new ReentrantLock();
// 队列满了时,添加元素操作将阻塞在此条件上
private final Condition notFull = putLock.newCondition();
// 默认构造函数,队列默认大小为Integer.MAX_VALUE
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(); // 获取put锁
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(); // 释放put锁
}
}
}
可以看到,与ArraryBlocking不同,LinkedBlockingQueue有两把锁,添加/删除操作各一把,这样可以提供提高吞吐量。
add(E,e)方法,来自于其父类AbstractQueue的实现。添加元素成功返回true,否则抛出异常。其实际是调用offer方法,offer方法由LinkedBlockingQueue自己实现
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full&#