LinkedBlockingQueue:线程安全的有界队列¶
一、是什么¶
基于链表的阻塞队列,默认容量 Integer.MAX_VALUE(建议指定)。
二、结构¶
- 两个锁:takeLock(读)、putLock(写)。
- 两个条件:notEmpty(读等待)、notFull(写等待)。
三、源码结构¶
public class LinkedBlockingQueue<E> {
static class Node<E> { E item; Node<E> next; }
private final int capacity;
private final AtomicInteger count = new AtomicInteger();
private final ReentrantLock takeLock = new ReentrantLock();
private final Condition notEmpty = takeLock.newCondition();
private final ReentrantLock putLock = new ReentrantLock();
private final Condition notFull = putLock.newCondition();
}
四、为什么用两个锁¶
ArrayBlockingQueue 用一个锁,读写互斥。LinkedBlockingQueue 用两个锁,读和写可以并行,吞吐更高。
五、put 流程¶
public void put(E e) throws InterruptedException {
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(); // 有元素了,唤醒读
}
六、take 流程¶
对称:拿 takeLock → 空了等 notEmpty → 取 head → count 减 → 唤醒 notFull。
七、对比 ArrayBlockingQueue¶
| LinkedBlockingQueue | ArrayBlockingQueue | |
|---|---|---|
| 结构 | 链表 | 数组 |
| 锁 | 读写双锁 | 单锁 |
| 吞吐 | 高(读写并行) | 低(读写互斥) |
| 容量 | 默认无界 | 必须指定 |
| GC | 节点对象 | 数组连续 |
线程池用哪个
Executors.newFixedThreadPool 用 LinkedBlockingQueue(无界)。 Executors.newCachedThreadPool 用 SynchronousQueue(不存元素)。