LinkedBlockingQueue是一个由单向链表实现的阻塞队列,该队列按照先进先出的原则对元素进行排序。队尾插入元素,对头删除元素。在构造LinkedBlockingQueue时可以指定容量大小,若未指定元素,则容量大小为Integer.MAX_VALUE.
1.以下为LinkedBlockingQueue的属性
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; }
}
/** The capacity bound, or Integer.MAX_VALUE if none */
private final int capacity;
/** Current number of elements */
private final AtomicInteger count = new AtomicInteger(0);//队列中元素的个数
/**
* Head of linked list.
* Invariant: head.item == null
*/
private transient Node<E> head;//头节点,
/**
* Tail of linked list.
* Invariant: last.next == null
*/
private transient Node<E> last;//尾节点
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();//取出锁
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();//非空条件
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();//插入锁
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();//非满条件
LinkedBlockingQueue采用两把锁,takeLock和putLock .对插入元素和取出元素采用不同的锁,提高并发性。
以下主要分析put与take操作
2.put函数源码分析:
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
Node<E> node = new Node(e);//插入元素时会new 出一个Node对象,影响性能
final ReentrantLock putLock = this.putLock;//使用putLock锁进行互斥操作
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
/*
* Note that count is used in wait guard even though it is
* not protected by lock. This works because count can
* only decrease at this point (all other puts are shut
* out by lock), and we (or some other waiting put) are
* signalled if it ever changes from capacity. Similarly
* for all other uses of count in other wait guards.
*/
while (count.get() == capacity) {//当队列满时,线程阻塞与notFull条件变量
notFull.await();
}
enqueue(node);//插入元素node
c = count.getAndIncrement();//把在执行插入元素操作之前的队列元素个数赋给c ,count再增一
if (c + 1 < capacity)//如果在插入元素之后,队列元素的个数小于capacity,说明队列还可以执行Put操作,本put
//本put线程唤醒其他被阻塞的put线程
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)//在插入此元素之前若c为零,说明可能会有take线程被阻塞,则唤醒被阻塞的take线程
signalNotEmpty();
}
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
notEmpty.signal();
} finally {
takeLock.unlock();
}
}
3.take()源码分析
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;//采用takeLock
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {//当队列为空时,take线程阻塞
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();//获得执行删除元素之前,队列中元素的个数
if (c > 1)//若c>1说明队列中还有元素 ,则唤醒被阻塞的take线程
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)//在删除元素之前,队列已满,唤醒被阻塞的put线程
signalNotFull();
return x;
}
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
notFull.signal();
} finally {
putLock.unlock();
}
}