类的描述
public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, Serializable
基于链接Node的可选有界阻塞队列。该队列对元素进行FIFO排序(先进先出)。队列的头是在队列上停留时间最长的元素。队列的尾部是在队列上停留时间最短的元素。新元素插入到队列的尾部,队列检索操作获取队列头部的元素。链接队列通常比基于阵列的队列具有更高的吞吐量,但在大多数并发应用程序中性能不太可预测。
可选的capacity-bound构造函数参数用作防止队列过度扩展的方法。容量(如果未指定)等于Integer.MAX_VALUE。链接节点在每次插入时动态创建,除非这会使队列超出容量。
此类及其迭代器实现集合和迭代器接口的所有可选方法。
常量、变量、静态内部类
static class Node<E> {
E item;
/**
* One of:
* - the real successor Node
* - this Node, meaning the successor is head.next
* - null, meaning there is no successor (this is the last node)
*/
Node<E> next;
Node(E x) { item = x; }
}
// 容量,如果未指定为Integer.MAX_VALUE
private final int capacity;
/** 当前元素的数量 */
/** AtomicInteger 可以保证线程安全,通过unsafe来实现的 */
private final AtomicInteger count = new AtomicInteger();
/**
* 头节点
* Invariant: head.item == null
*/
transient Node<E> head;
/**
* T尾节点
* Invariant: last.next == null
*/
private transient Node<E> last;
/** task的锁 */
private final ReentrantLock takeLock = new ReentrantLock();
/** 等待tasks的队列 */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
/** 等待put的队列 */
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(); // Never contended, but necessary for visibility
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();
}
}
//设置链表并,指定last指针
private void enqueue(Node<E> node) {
// assert putLock.isHeldByCurrentThread();
// assert last.next == null;
last = last.next = node;
}
队列中常用的方法
add
//父类AbstractQueue的add
public boolean add(E e) {
if (offer(e)) //LinkedBlockingQueue的offer
return true;
else
throw new IllegalStateException("Queue full");
}
offer
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
if (count.get() == capacity) //判断当前元素是否到达容量最大值
return false;
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock; //元素put锁
putLock.lock(); //获取锁
try {
if (count.get() < capacity) {
enqueue(node); //在链表尾部添加元素
c = count.getAndIncrement(); //count + 1 c 等于count的旧值
if (c + 1 < capacity)
//如果+1 《 容量最大值 通知notFull队列
notFull.signal();
}
} finally {
putLock.unlock(); // s释放锁
}
if (c == 0)
signalNotEmpty();
return c >= 0;
}
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
// 通知notEmpty队列
notEmpty.signal();
} finally {
takeLock.unlock();
}
}
poll
public E poll() {
final AtomicInteger count = this.count;
if (count.get() == 0) //判断队列是否为空
return null;
E x = null;
int c = -1;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock(); // 获取takeLock锁
try {
if (count.get() > 0) {
x = dequeue();
c = count.getAndDecrement(); // count - 1 , c为count的原始值
if (c > 1)
notEmpty.signal();
}
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
//等待一定的时间poll
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
E x = null;
int c = -1;
long nanos = unit.toNanos(timeout);
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
if (nanos <= 0) //如果nanos<=0 和poll()一样的效果,当前队列为空直接返回
return null;
nanos = notEmpty.awaitNanos(nanos); // 等待notEmpty被唤醒
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal(); // 唤醒notEmpty
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull(); //notFull唤醒
return x;
}
private E dequeue() {
// assert takeLock.isHeldByCurrentThread();
// assert head.item == null;
//将头节点移除链表
Node<E> h = head;
Node<E> first = h.next;
h.next = h; // 要移除的元素自己指向自己,帮助GC
head = first; //head 节点变为first,
E x = first.item;
first.item = null; head / first的节点的元素为空
return x;
}
remove
// AbstractQueue的Remove
public E remove() {
E x = poll(); //调用的poll
if (x != null)
return x;
else
throw new NoSuchElementException();
}
public boolean remove(Object o) {
if (o == null) return false;
fullyLock(); // putLock.lock(); takeLock.lock();
try {
for (Node<E> trail = head, p = trail.next;
p != null;
trail = p, p = p.next) { //遍历链表
if (o.equals(p.item)) {
unlink(p, trail);
return true;
}
}
return false;
} finally {
fullyUnlock(); // takeLock.unlock(); putLock.unlock();
}
}
void unlink(Node<E> p, Node<E> trail) {
// assert isFullyLocked();
// p.next is not changed, to allow iterators that are
// traversing p to maintain their weak-consistency guarantee.
p.item = null;
//替换p节点上一个节点的next指针,保证链表的正确
trail.next = p.next;
if (last == p)
last = trail;
if (count.getAndDecrement() == capacity)
notFull.signal();
}
take
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
notEmpty.await(); // 等待元素添加
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal(); //notEmpty被唤醒
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull(); // notFull被唤醒
return x;
}
peek
public E peek() {
if (count.get() == 0)
return null;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
Node<E> first = head.next;
if (first == null)
return null;
else
return first.item;
} finally {
takeLock.unlock();
}
}
element
// AbstractQueue的peek
public E element() {
E x = peek();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
结论:
1. LinkedBlockingQueue是通过Node节点组成的单向链表来存储数据的, 且可以指定最大容量,如果指定,最大容量为 Integer.MAX_VALUE
2. 链表的头节点是head节点,单head节点并不是队列的第一个元素, head.next是队列的第一个元素
3. ReentrantLock takeLock 保证弹出元素线程安全, ReentrantLock putLock 保证put元素的线程安全
4. Condition notEmpty 来实现等待弹出元素, Condition notFull 来实现等待put元素