LinkedBlockingQueue:该类实现了BlockingQueue接口,采用链接的Node作为数据结构,在弹出队列时,采用FIFO的策略,存储默认数据量为 Integer.MAX_VALUE。接下来看一下它的部分实现方法:
/**
*数据结构
**/
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
下面的两个锁很重要,在队列的出和入中实现阻塞:
//取数据或出队列锁
private final ReentrantLock takeLock = new ReentrantLock();
//入队列锁
private final ReentrantLock putLock = new ReentrantLock();
//线程交互条件锁take
private final Condition notEmpty = takeLock.newCondition();
//线程交互条件锁put
private final Condition notFull = putLock.newCondition();
入队列方法:
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
int c = -1;
Node<E> node = new Node(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();//放置锁
try {
while (count.get() == capacity) {
//如果队列满了,等待信号
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();//通知阻塞的入队列线程往里放数据
} finally {
putLock.unlock();//释放锁
}
if (c == 0)
signalNotEmpty();//通知阻塞的出队列线程来拿数据
}
对于入队列的具体方法很简单:
private void enqueue(Node<E> node) {
last = last.next = node;
}
接下来看一下出队列的方法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();
try {
if (count.get() > 0) {
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
}
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
因为采用链表的方式,并且使用入队列和出队列分为两个锁,所以存取的时候比ArrayBlockingQueue要快一些。