LinkedBlockingQueue简介
-
Linked:由链表实现,Blocking:支持阻塞获取和添加,Queue:一个队列
-
和经典的生产者消费者不同的是:生产者和消费者各使用一把锁
-
生产者阻塞后由大概率由生产者唤醒,小概率被消费者唤醒,消费者同理
//队列结点
static class Node {
E item;
Node next;
Node(E x) { item = x; }
}
//队列容量
private final int capacity;
//结点数量
private final AtomicInteger count = new AtomicInteger();
//头结点
transient Node head;
//尾结点
private transient Node last;
//take,poll操作使用的锁
private final ReentrantLock takeLock = new ReentrantLock();
//当take,poll条件不满足时,使用notEmpty队列等待
private final Condition notEmpty = takeLock.newCondition();
//put,offer操作使用的锁
private final ReentrantLock putLock = new ReentrantLock();
//当put,offer条件不满足时,使用notFull队列等待
private final Condition notFull = putLock.newCondition();
//初始化容量为Intger最大值
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
//构造函数:初始化容量和头尾结点
//头结点不存储值
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node(null);
}
解析put()和offer()
public void put(E e) throws InterruptedException {
//空指针异常
if (e == null) throw new NullPointerException();
//count
int c = -1;
//把要放入的值包装成Node结点
Node node = new Node(e);
//put锁
final ReentrantLock putLock = this.putLock;
//队列中的结点数目
final AtomicInteger count = this.count;
//拿锁,具体见AQS源码阅读(一)
putLock.lockInterruptibly();
try {
//队列满了,去notFull队列等待,await()操作具体见AQS源码阅读(二)
while (count.get() == capacity) {
notFull.await();
}
//更新尾结点:将结点入队
enqueue(node);
//count自增一
c = count.getAndIncrement();
//此时队列还有容量,可以添加,去唤醒notFull队列中的结点,signal()操作具体见AQS源码阅读(二)
if (c + 1 < capacity)
notFull.signal();
} finally {
//解锁,具体见AQS源码阅读(一)
putLock.unlock();
}
if (c == 0)
//什么时候c == 0?
//当前线程添加时队列为空,消费者都阻塞了,需要由生产者去唤醒消费者
signalNotEmpty();
}
//更新尾结点:将node入队
private void enqueue(Node node) {
// assert putLock.isHeldByCurrentThread();
// assert last.next == null;
last = last.next = node;
}
//唤醒notEmpty队列中的一个结点
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
notEmpty.signal();
} finally {
takeLock.unlock();
}
}
//和put()不同,offer操作不会阻塞,如果无法添加就返回了
public boolean offer(E e) {
//空指针异常
if (e == null) throw new NullPointerException();
//队列中的结点数目
final AtomicInteger count = this.count;
//队列容量已满,直接返回
if (count.get() == capacity)
return false;
//count
int c = -1;
//把要放入的值包装成Node结点
Node node = new Node(e);
//put锁
final ReentrantLock putLock = this.putLock;
//拿锁
putLock.lock();
try {
//添加结点
if (count.get() < capacity) {
enqueue(node);
//count自增一
c = count.getAndIncrement();
//此时队列还有容量,可以添加,去唤醒notFull队列中的结点
if (c + 1 < capacity)
notFull.signal();
}
} finally {
//解锁
putLock.unlock();
}
if (c == 0)
//什么时候c == 0?
//当前线程添加时队列为空,消费者都阻塞了,需要由生产者去唤醒消费者
signalNotEmpty();
//如果添加成功会更新c
return c >= 0;
}
解析take()和poll()
public E take() throws InterruptedException {
//要拿的值
E x;
//count
int c = -1;
//队列中的结点数目
final AtomicInteger count = this.count;
//take锁
final ReentrantLock takeLock = this.takeLock;
//拿锁
takeLock.lockInterruptibly();
try {
//队列为空,去notEmpty队列等待
while (count.get() == 0) {
notEmpty.await();
}
//从head.next处取值,并更新head
x = dequeue();
//count自减一
c = count.getAndDecrement();
//此时队列还可以拿,去唤醒notEmpty队列中的结点
if (c > 1)
notEmpty.signal();
} finally {
//解锁
takeLock.unlock();
}
//什么时候c == capacity?
//当前线程消费时队列满载,生产者都阻塞了,需要由消费者去唤醒生产者
if (c == capacity)
signalNotFull();
return x;
}
//从head.next处取值,更新头结点
private E dequeue() {
// assert takeLock.isHeldByCurrentThread();
// assert head.item == null;
Node h = head;
Node first = h.next;
h.next = h; // help GC
head = first;
E x = first.item;
first.item = null;
return x;
}
//唤醒notFull队列中的一个结点
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
notFull.signal();
} finally {
putLock.unlock();
}
}
public E poll() {
//队列中的结点数目
final AtomicInteger count = this.count;
//队列为空,直接返回
if (count.get() == 0)
return null;
//要拿的值
E x = null;
//count
int c = -1;
//take锁
final ReentrantLock takeLock = this.takeLock;
//拿锁
takeLock.lock();
try {
if (count.get() > 0) {
//从head.next处取值,并更新head
x = dequeue();
//count自减一
c = count.getAndDecrement();
if (c > 1)
//此时队列还可以拿,去唤醒notEmpty队列中的结点
notEmpty.signal();
}
} finally {
//解锁
takeLock.unlock();
}
//什么时候c == capacity?
//当前线程消费时队列满载,生产者都阻塞了,需要由消费者去唤醒生产者
if (c == capacity)
signalNotFull();
return x;
}