阻塞队列
1. 阻塞队列概述
1.1 什么是阻塞队列
阻塞队列(BlockingQueue)是Java并发包中的重要组件,它在普通队列的基础上增加了阻塞功能:
- 生产者阻塞:当队列满时,生产者线程会被阻塞,直到队列有空间
- 消费者阻塞:当队列空时,消费者线程会被阻塞,直到队列有元素
1.2 阻塞队列的核心特性
graph TB
A[阻塞队列核心特性] --> B[线程安全]
A --> C[阻塞机制]
A --> D[容量控制]
A --> E[多种操作模式]
B --> B1[内部使用锁机制]
B --> B2[原子操作保证]
C --> C1[put/take阻塞]
C --> C2[offer/poll超时]
D --> D1[有界队列]
D --> D2[无界队列]
E --> E1[抛异常模式]
E --> E2[返回特殊值]
E --> E3[阻塞模式]
E --> E4[超时模式]
1.3 Java中的阻塞队列实现
classDiagram
class BlockingQueue {
<<interface>>
+put(E e)
+take() E
+offer(E e) boolean
+poll() E
+offer(E e, long timeout, TimeUnit unit) boolean
+poll(long timeout, TimeUnit unit) E
+remainingCapacity() int
+drainTo(Collection c) int
}
class BlockingDeque {
<<interface>>
+putFirst(E e)
+putLast(E e)
+takeFirst() E
+takeLast() E
+offerFirst(E e, long timeout, TimeUnit unit) boolean
+offerLast(E e, long timeout, TimeUnit unit) boolean
+pollFirst(long timeout, TimeUnit unit) E
+pollLast(long timeout, TimeUnit unit) E
}
class ArrayBlockingQueue {
-Object[] items
-int takeIndex
-int putIndex
-int count
-ReentrantLock lock
-Condition notEmpty
-Condition notFull
}
class LinkedBlockingQueue {
-Node~E~ head
-Node~E~ last
-AtomicInteger count
-ReentrantLock takeLock
-ReentrantLock putLock
-Condition notEmpty
-Condition notFull
}
class PriorityBlockingQueue {
-Object[] queue
-int size
-Comparator~E~ comparator
-ReentrantLock lock
-Condition notEmpty
}
class SynchronousQueue {
-Transferer~E~ transferer
}
class LinkedBlockingDeque {
-Node~E~ first
-Node~E~ last
-int count
-int capacity
-ReentrantLock lock
-Condition notEmpty
-Condition notFull
}
BlockingQueue <|-- BlockingDeque
BlockingQueue <|.. ArrayBlockingQueue
BlockingQueue <|.. LinkedBlockingQueue
BlockingQueue <|.. PriorityBlockingQueue
BlockingQueue <|.. SynchronousQueue
BlockingDeque <|.. LinkedBlockingDeque
2. BlockingQueue 接口分析
2.1 接口定义与核心方法
从项目源码 BlockingQueue.java
中可以看到接口的完整定义:
/**
* 阻塞队列接口 - 扩展了Queue接口,增加了阻塞操作
* 支持四种操作模式:抛异常、返回特殊值、阻塞、超时
*/
public interface BlockingQueue<E> extends Queue<E> {
// ========== 插入操作 ==========
/**
* 立即插入元素,成功返回true,容量不足抛IllegalStateException
* 对应操作模式:抛异常
*/
boolean add(E e);
/**
* 立即插入元素,成功返回true,容量不足返回false
* 对应操作模式:返回特殊值
*/
boolean offer(E e);
/**
* 插入元素,必要时等待空间可用
* 对应操作模式:阻塞
*/
void put(E e) throws InterruptedException;
/**
* 插入元素,等待指定时间,超时返回false
* 对应操作模式:超时
*/
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;
// ========== 移除操作 ==========
/**
* 移除并返回队头元素,必要时等待元素可用
* 对应操作模式:阻塞
*/
E take() throws InterruptedException;
/**
* 移除并返回队头元素,等待指定时间,超时返回null
* 对应操作模式:超时
*/
E poll(long timeout, TimeUnit unit) throws InterruptedException;
// ========== 检查操作 ==========
/**
* 返回队列剩余容量,无限制返回Integer.MAX_VALUE
*/
int remainingCapacity();
/**
* 移除指定元素的一个实例(如果存在)
*/
boolean remove(Object o);
/**
* 检查队列是否包含指定元素
*/
boolean contains(Object o);
// ========== 批量操作 ==========
/**
* 移除所有可用元素并添加到指定集合
* 比重复调用poll()更高效
*/
int drainTo(Collection<? super E> c);
/**
* 移除最多指定数量的元素并添加到指定集合
*/
int drainTo(Collection<? super E> c, int maxElements);
}
2.2 四种操作模式对比
graph TB
subgraph "插入操作"
A1[add - 抛异常] --> A1R[成功:true<br/>失败:IllegalStateException]
A2[offer - 特殊值] --> A2R[成功:true<br/>失败:false]
A3[put - 阻塞] --> A3R[成功:void<br/>失败:等待或InterruptedException]
A4[offer超时 - 超时] --> A4R[成功:true<br/>超时:false<br/>中断:InterruptedException]
end
subgraph "移除操作"
B1[remove - 抛异常] --> B1R[成功:元素<br/>失败:NoSuchElementException]
B2[poll - 特殊值] --> B2R[成功:元素<br/>失败:null]
B3[take - 阻塞] --> B3R[成功:元素<br/>失败:等待或InterruptedException]
B4[poll超时 - 超时] --> B4R[成功:元素<br/>超时:null<br/>中断:InterruptedException]
end
2.3 生产者-消费者模式示例
sequenceDiagram
participant P as 生产者线程
participant Q as BlockingQueue
participant C as 消费者线程
Note over P,C: 队列为空时的阻塞行为
C->>Q: take() - 尝试获取元素
Q-->>C: 阻塞等待...
P->>Q: put(element) - 插入元素
Q->>Q: 唤醒等待的消费者
Q-->>C: 返回元素
Note over P,C: 队列满时的阻塞行为
P->>Q: put(element) - 尝试插入
Q-->>P: 阻塞等待...
C->>Q: take() - 获取元素
Q->>Q: 唤醒等待的生产者
Q-->>P: 插入成功
3. BlockingDeque 接口分析
3.1 双端阻塞队列特性
从项目源码 BlockingDeque.java
中可以看到双端阻塞队列的完整定义:
/**
* 双端阻塞队列接口 - 同时继承BlockingQueue和Deque
* 支持在队列两端进行阻塞操作
*/
public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
// ========== 队头操作 ==========
/**
* 在队头插入元素,必要时等待空间可用
*/
void putFirst(E e) throws InterruptedException;
/**
* 在队头插入元素,等待指定时间
*/
boolean offerFirst(E e, long timeout, TimeUnit unit) throws InterruptedException;
/**
* 从队头移除元素,必要时等待元素可用
*/
E takeFirst() throws InterruptedException;
/**
* 从队头移除元素,等待指定时间
*/
E pollFirst(long timeout, TimeUnit unit) throws InterruptedException;
// ========== 队尾操作 ==========
/**
* 在队尾插入元素,必要时等待空间可用
*/
void putLast(E e) throws InterruptedException;
/**
* 在队尾插入元素,等待指定时间
*/
boolean offerLast(E e, long timeout, TimeUnit unit) throws InterruptedException;
/**
* 从队尾移除元素,必要时等待元素可用
*/
E takeLast() throws InterruptedException;
/**
* 从队尾移除元素,等待指定时间
*/
E pollLast(long timeout, TimeUnit unit) throws InterruptedException;
}
3.2 BlockingDeque与BlockingQueue方法映射
graph LR
subgraph "BlockingQueue方法"
BQ1[add/offer/put]
BQ2[remove/poll/take]
BQ3[element/peek]
end
subgraph "等价的BlockingDeque方法"
BD1[addLast/offerLast/putLast]
BD2[removeFirst/pollFirst/takeFirst]
BD3[getFirst/peekFirst]
end
BQ1 --> BD1
BQ2 --> BD2
BQ3 --> BD3
4. ArrayBlockingQueue 源码解析
4.1 核心数据结构
从项目源码 ArrayBlockingQueue.java
中可以看到其核心实现:
/**
* 基于数组的有界阻塞队列
* 特点:FIFO顺序、固定容量、可选公平性
*/
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
// ========== 核心字段 ==========
/** 存储队列元素的数组 - 固定大小 */
final Object[] items;
/** 下次take、poll、peek或remove操作的索引位置 */
int takeIndex;
/** 下次put、offer或add操作的索引位置 */
int putIndex;
/** 队列中元素的数量 */
int count;
// ========== 并发控制 ==========
/** 保护所有访问的主锁 */
final ReentrantLock lock;
/** 等待take操作的条件队列 - 队列非空条件 */
private final Condition notEmpty;
/** 等待put操作的条件队列 - 队列非满条件 */
private final Condition notFull;
/** 当前活跃迭代器的共享状态 */
transient Itrs itrs;
}
4.2 构造方法分析
/**
* 构造指定容量的ArrayBlockingQueue
* @param capacity 队列容量,必须大于0
* @param fair 是否使用公平锁,默认false(非公平)
*/
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
// 初始化固定大小的数组
this.items = new Object[capacity];
// 创建可重入锁,支持公平/非公平模式
lock = new ReentrantLock(fair);
// 基于锁创建条件队列
notEmpty = lock.newCondition(); // 队列非空条件
notFull = lock.newCondition(); // 队列非满条件
}
/**
* 构造指定容量和初始元素的ArrayBlockingQueue
*/
public ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c) {
this(capacity, fair);
final ReentrantLock lock = this.lock;
lock.lock(); // 确保可见性,不是为了互斥
try {
final Object[] items = this.items;
int i = 0;
try {
// 将集合中的元素复制到数组中
for (E e : c)
items[i++] = Objects.requireNonNull(e);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i; // 设置元素数量
putIndex = (i == capacity) ? 0 : i; // 设置下次插入位置
} finally {
lock.unlock();
}
}
4.3 核心操作方法
4.3.1 入队操作 - put方法
/**
* 阻塞式插入元素 - 队列满时等待
*/
public void put(E e) throws InterruptedException {
Objects.requireNonNull(e); // 不允许null元素
final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); // 可中断的锁获取
try {
// 队列满时,在notFull条件上等待
while (count == items.length)
notFull.await();
enqueue(e); // 执行入队操作
} finally {
lock.unlock();
}
}
/**
* 非阻塞式插入元素 - 队列满时返回false
*/
public boolean offer(E e) {
Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false; // 队列满,直接返回false
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
/**
* 超时插入元素 - 在指定时间内等待空间
*/
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
Objects.requireNonNull(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
if (nanos <= 0L)
return false; // 超时返回false
// 在notFull条件上等待指定时间
nanos = notFull.awaitNanos(nanos);
}
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
4.3.2 出队操作 - take方法
/**
* 阻塞式获取元素 - 队列空时等待
*/
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
// 队列空时,在notEmpty条件上等待
while (count == 0)
notEmpty.await();
return dequeue(); // 执行出队操作
} finally {
lock.unlock();
}
}
/**
* 非阻塞式获取元素 - 队列空时返回null
*/
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
/**
* 超时获取元素 - 在指定时间内等待元素
*/
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0) {
if (nanos <= 0L)
return null; // 超时返回null
// 在notEmpty条件上等待指定时间
nanos = notEmpty.awaitNanos(nanos);
}
return dequeue();
} finally {
lock.unlock();
}
}
4.4 内部辅助方法
/**
* 循环递增索引 - 实现环形数组
*/
final int inc(int i) {
return (++i == items.length) ? 0 : i;
}
/**
* 循环递减索引
*/
final int dec(int i) {
return ((i == 0) ? items.length : i) - 1;
}
/**
* 入队操作 - 在putIndex位置插入元素
* 调用前必须持有锁
*/
private void enqueue(E e) {
final Object[] items = this.items;
items[putIndex] = e; // 在putIndex位置放入元素
if (++putIndex == items.length) // 更新putIndex,实现环形
putIndex = 0;
count++; // 增加元素计数
notEmpty.signal(); // 唤醒等待获取元素的线程
}
/**
* 出队操作 - 从takeIndex位置移除元素
* 调用前必须持有锁
*/
private E dequeue() {
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E e = (E) items[takeIndex]; // 获取takeIndex位置的元素
items[takeIndex] = null; // 清空引用,帮助GC
if (++takeIndex == items.length) // 更新takeIndex,实现环形
takeIndex = 0;
count--; // 减少元素计数
if (itrs != null)
itrs.elementDequeued(); // 通知迭代器元素被移除
notFull.signal(); // 唤醒等待插入元素的线程
return e;
}
4.5 ArrayBlockingQueue内存结构图
flowchart TB
subgraph ABQ ["ArrayBlockingQueue内存结构"]
A[ArrayBlockingQueue实例]
subgraph Fields ["核心字段"]
B["Object[] items<br/>存储数组"]
C["int takeIndex<br/>取元素索引"]
D["int putIndex<br/>放元素索引"]
E["int count<br/>元素数量"]
end
subgraph Locks ["并发控制"]
F["ReentrantLock lock<br/>主锁"]
G["Condition notEmpty<br/>非空条件"]
H["Condition notFull<br/>非满条件"]
end
subgraph Array ["数组状态示例"]
B1["[0] element1"]
B2["[1] element2"]
B3["[2] null"]
B4["[3] null"]
end
A --> Fields
A --> Locks
B -.-> Array
C -.-> |"指向位置 0"| B1
D -.-> |"指向位置 2"| B3
E -.-> |"当前数量: 2"| Array
end
4.6 环形数组工作原理
sequenceDiagram
participant T as 线程
participant A as ArrayBlockingQueue
participant Arr as items数组
Note over T,Arr: 初始状态:takeIndex=0, putIndex=0, count=0
T->>A: put("A")
A->>Arr: items[0] = "A"
A->>A: putIndex = 1, count = 1
T->>A: put("B")
A->>Arr: items[1] = "B"
A->>A: putIndex = 2, count = 2
T->>A: take()
A->>Arr: 获取items[0] = "A"
A->>Arr: items[0] = null
A->>A: takeIndex = 1, count = 1
Note over T,Arr: 当putIndex到达数组末尾时,重置为0(环形)
T->>A: put("C") [假设数组长度为3]
A->>Arr: items[2] = "C"
A->>A: putIndex = 0 (环形重置), count = 2
4.7 ArrayBlockingQueue特性总结
- 有界队列:容量固定,防止内存溢出
- FIFO顺序:先进先出,保证公平性
- 单锁设计:所有操作共享一个锁,简单但可能成为瓶颈
- 环形数组:高效的内存利用,避免数组移动
- 条件队列:使用Condition实现精确的线程唤醒
- 可选公平性:支持公平/非公平锁模式
5. LinkedBlockingQueue 源码解析
5.1 核心数据结构
从项目源码 LinkedBlockingQueue.java
中可以看到其基于链表的实现:
/**
* 基于链表的可选有界阻塞队列
* 特点:FIFO顺序、可选容量限制、双锁设计
*/
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
// ========== 节点定义 ==========
/**
* 链表节点 - 单向链表结构
*/
static class Node<E> {
E item; // 节点存储的元素
Node<E> next; // 指向下一个节点的指针
Node(E x) { item = x; }
}
// ========== 核心字段 ==========
/** 队列容量,默认Integer.MAX_VALUE */
private final int capacity;
/** 当前队列中的元素数量 - 使用原子整数 */
private final AtomicInteger count = new AtomicInteger();
/** 队列头节点 - 虚拟头节点,不存储实际数据 */
transient Node<E> head;
/** 队列尾节点 - 指向最后一个实际节点 */
private transient Node<E> last;
// ========== 双锁设计 ==========
/** take操作的锁 - 保护头部操作 */
private final ReentrantLock takeLock = new ReentrantLock();
/** 等待take操作的条件队列 */
private final Condition notEmpty = takeLock.newCondition();
/** put操作的锁 - 保护尾部操作 */
private final ReentrantLock putLock = new ReentrantLock();
/** 等待put操作的条件队列 */
private final Condition notFull = putLock.newCondition();
}
5.2 构造方法分析
/**
* 构造无界LinkedBlockingQueue(容量为Integer.MAX_VALUE)
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
/**
* 构造指定容量的LinkedBlockingQueue
*/
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
// 初始化虚拟头节点
last = head = new Node<E>(null);
}
/**
* 构造包含指定集合元素的LinkedBlockingQueue
*/
public LinkedBlockingQueue(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
final ReentrantLock putLock = this.putLock;
putLock.lock(); // 确保可见性
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();
}
}
5.3 双锁机制核心操作
5.3.1 入队操作 - put方法
/**
* 阻塞式插入元素 - 使用putLock
*/
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
final int c;
final Node<E> node = new Node<E>(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(); // 原子递增计数
// 如果队列还有空间,唤醒其他等待put的线程
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
// 如果这是第一个元素,唤醒等待take的线程
if (c == 0)
signalNotEmpty();
}
/**
* 入队操作 - 在链表尾部添加节点
* 调用前必须持有putLock
*/
private void enqueue(Node<E> node) {
// 将新节点链接到链表尾部
last = last.next = node;
}
/**
* 唤醒等待take的线程
* 需要获取takeLock来安全地访问notEmpty条件
*/
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
notEmpty.signal();
} finally {
takeLock.unlock();
}
}
5.3.2 出队操作 - take方法
/**
* 阻塞式获取元素 - 使用takeLock
*/
public E take() throws InterruptedException {
final E x;
final int c;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
// 队列空时等待
while (count.get() == 0) {
notEmpty.await();
}
x = dequeue(); // 执行出队
c = count.getAndDecrement(); // 原子递减计数
// 如果队列还有元素,唤醒其他等待take的线程
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
// 如果队列有空间了,唤醒等待put的线程
if (c == capacity)
signalNotFull();
return x;
}
/**
* 出队操作 - 从链表头部移除节点
* 调用前必须持有takeLock
*/
private E dequeue() {
Node<E> h = head; // 获取虚拟头节点
Node<E> first = h.next; // 获取第一个实际节点
h.next = h; // 帮助GC
head = first; // 更新头节点
E x = first.item; // 获取元素
first.item = null; // 清空引用
return x;
}
/**
* 唤醒等待put的线程
* 需要获取putLock来安全地访问notFull条件
*/
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
notFull.signal();
} finally {
putLock.unlock();
}
}
5.4 LinkedBlockingQueue内存结构图
graph TB
subgraph "LinkedBlockingQueue内存结构"
A[LinkedBlockingQueue] --> B[Node head - 虚拟头节点]
A --> C[Node last - 尾节点]
A --> D[AtomicInteger count]
A --> E[ReentrantLock takeLock]
A --> F[ReentrantLock putLock]
A --> G[Condition notEmpty]
A --> H[Condition notFull]
B --> B1["item: null<br/>next: →"]
B1 --> B2["item: element1<br/>next: →"]
B2 --> B3["item: element2<br/>next: →"]
B3 --> B4["item: element3<br/>next: null"]
C --> B4
D --> D1["当前元素数量: 3"]
E --> E1["保护头部操作"]
F --> F1["保护尾部操作"]
G --> G1["队列非空条件"]
H --> H1["队列非满条件"]
end
5.5 双锁机制优势分析
sequenceDiagram
participant P1 as 生产者线程1
participant P2 as 生产者线程2
participant Q as LinkedBlockingQueue
participant C1 as 消费者线程1
participant C2 as 消费者线程2
Note over P1,C2: 双锁允许并发的put和take操作
par 并发put操作
P1->>Q: put("A") - 获取putLock
Q->>Q: enqueue at tail
and
P2->>Q: put("B") - 等待putLock
and 并发take操作
C1->>Q: take() - 获取takeLock
Q->>Q: dequeue from head
and
C2->>Q: take() - 等待takeLock
end
Note over P1,C2: put和take可以同时进行,提高并发性
5.6 LinkedBlockingQueue特性总结
- 可选有界:可以指定容量,默认无界(Integer.MAX_VALUE)
- 双锁设计:putLock和takeLock分离,提高并发性
- 链表结构:动态内存分配,适合大容量场景
- 原子计数:使用AtomicInteger保证count的线程安全
- 虚拟头节点:简化链表操作,避免特殊情况处理
- FIFO顺序:严格的先进先出顺序
6. PriorityBlockingQueue 源码解析
6.1 核心数据结构
从项目源码 PriorityBlockingQueue.java
中可以看到其基于堆的实现:
/**
* 基于优先级堆的无界阻塞队列
* 特点:优先级排序、无界容量、单锁设计
*/
public class PriorityBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
// ========== 核心字段 ==========
/** 默认初始容量 */
private static final int DEFAULT_INITIAL_CAPACITY = 11;
/** 最大数组大小 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/** 存储队列元素的数组 - 二叉堆结构 */
private transient Object[] queue;
/** 队列中元素的数量 */
private transient int size;
/** 元素比较器,null表示使用自然排序 */
private transient Comparator<? super E> comparator;
/** 保护所有公共操作的锁 */
private final ReentrantLock lock;
/** 等待take操作的条件队列 */
private final Condition notEmpty;
/**
* 用于分配的自旋锁(通过CAS操作)
* 在扩容时使用,避免多个线程同时扩容
*/
private transient volatile int allocationSpinLock;
/**
* 普通PriorityQueue,用于序列化/反序列化
* 仅在序列化时使用
*/
private PriorityQueue<E> q;
}
6.2 构造方法分析
/**
* 构造默认容量的PriorityBlockingQueue
*/
public PriorityBlockingQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
/**
* 构造指定初始容量的PriorityBlockingQueue
*/
public PriorityBlockingQueue(int initialCapacity) {
this(initialCapacity, null);
}
/**
* 构造指定初始容量和比较器的PriorityBlockingQueue
*/
public PriorityBlockingQueue(int initialCapacity,
Comparator<? super E> comparator) {
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
this.comparator = comparator;
this.queue = new Object[initialCapacity];
}
/**
* 构造包含指定集合元素的PriorityBlockingQueue
*/
public PriorityBlockingQueue(Collection<? extends E> c) {
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
boolean heapify = true; // 是否需要堆化
boolean screen = true; // 是否需要检查null
if (c instanceof SortedSet<?>) {
SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
this.comparator = (Comparator<? super E>) ss.comparator();
heapify = false;
}
else if (c instanceof PriorityBlockingQueue<?>) {
PriorityBlockingQueue<? extends E> pq =
(PriorityBlockingQueue<? extends E>) c;
this.comparator = (Comparator<? super E>) pq.comparator();
screen = false;
if (pq.getClass() == PriorityBlockingQueue.class)
heapify = false;
}
Object[] es = c.toArray();
int n = es.length;
// 检查null元素
if (screen && (n == 1 || this.comparator != null)) {
for (Object e : es) {
if (e == null)
throw new NullPointerException();
}
}
this.queue = ensureNonEmpty(es);
this.size = n;
// 如果需要,进行堆化
if (heapify)
heapify();
}
6.3 核心操作方法
6.3.1 入队操作 - put方法
/**
* 插入元素 - 由于是无界队列,put永远不会阻塞
*/
public void put(E e) {
offer(e); // 直接调用offer,因为无界队列不会满
}
/**
* 非阻塞插入元素
*/
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock();
int n, cap;
Object[] es;
// 检查是否需要扩容
while ((n = size) >= (cap = (es = queue).length))
tryGrow(es, cap);
try {
final Comparator<? super E> cmp;
if ((cmp = comparator) == null)
siftUpComparable(n, e, es); // 使用自然排序上浮
else
siftUpUsingComparator(n, e, es, cmp); // 使用比较器上浮
size = n + 1;
notEmpty.signal(); // 唤醒等待的消费者
} finally {
lock.unlock();
}
return true;
}
/**
* 使用自然排序进行上浮操作
* 维护最小堆性质
*/
private static <T> void siftUpComparable(int k, T x, Object[] es) {
Comparable<? super T> key = (Comparable<? super T>) x;
while (k > 0) {
int parent = (k - 1) >>> 1; // 父节点索引
Object e = es[parent];
if (key.compareTo((T) e) >= 0) // 已满足堆性质
break;
es[k] = e; // 父节点下移
k = parent; // 继续向上比较
}
es[k] = key; // 插入到正确位置
}
/**
* 使用比较器进行上浮操作
*/
private static <T> void siftUpUsingComparator(
int k, T x, Object[] es, Comparator<? super T> cmp) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = es[parent];
if (cmp.compare(x, (T) e) >= 0)
break;
es[k] = e;
k = parent;
}
es[k] = x;
}
6.3.2 出队操作 - take方法
/**
* 阻塞式获取并移除队头元素(优先级最高的元素)
*/
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
E result;
try {
// 队列空时等待
while ((result = dequeue()) == null)
notEmpty.await();
} finally {
lock.unlock();
}
return result;
}
/**
* 非阻塞获取并移除队头元素
*/
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return dequeue();
} finally {
lock.unlock();
}
}
/**
* 出队操作 - 移除堆顶元素并重新堆化
* 调用前必须持有锁
*/
private E dequeue() {
final Object[] es;
final E result;
if ((result = (E) ((es = queue)[0])) != null) {
final int n;
final E x = (E) es[(n = --size)]; // 获取最后一个元素
es[n] = null; // 清空最后位置
if (n > 0) {
final Comparator<? super E> cmp;
if ((cmp = comparator) == null)
siftDownComparable(0, x, es, n); // 自然排序下沉
else
siftDownUsingComparator(0, x, es, n, cmp); // 比较器下沉
}
}
return result;
}
/**
* 使用自然排序进行下沉操作
* 维护最小堆性质
*/
private static <T> void siftDownComparable(int k, T x, Object[] es, int n) {
Comparable<? super T> key = (Comparable<? super T>) x;
int half = n >>> 1; // 非叶子节点的边界
while (k < half) {
int child = (k << 1) + 1; // 左子节点
Object c = es[child];
int right = child + 1; // 右子节点
// 选择较小的子节点
if (right < n && ((Comparable<? super T>) c).compareTo((T) es[right]) > 0)
c = es[child = right];
if (key.compareTo((T) c) <= 0) // 已满足堆性质
break;
es[k] = c; // 子节点上移
k = child; // 继续向下比较
}
es[k] = key; // 插入到正确位置
}
6.4 动态扩容机制
/**
* 尝试扩容数组
* 使用自旋锁避免多线程同时扩容
*/
private void tryGrow(Object[] array, int oldCap) {
lock.unlock(); // 释放主锁,允许其他操作继续
Object[] newArray = null;
// 使用CAS获取扩容锁
if (allocationSpinLock == 0 &&
ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
try {
int newCap = oldCap + ((oldCap < 64) ?
(oldCap + 2) : // 小容量时快速增长
(oldCap >> 1)); // 大容量时增长50%
if (newCap - MAX_ARRAY_SIZE > 0) { // 检查溢出
int minCap = oldCap + 1;
if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
throw new OutOfMemoryError();
newCap = MAX_ARRAY_SIZE;
}
if (newCap > oldCap && queue == array)
newArray = new Object[newCap];
} finally {
allocationSpinLock = 0; // 释放扩容锁
}
}
// 如果当前线程没有获得扩容锁,让出CPU
if (newArray == null)
Thread.yield();
lock.lock(); // 重新获取主锁
// 如果扩容成功,复制数据
if (newArray != null && queue == array) {
queue = newArray;
System.arraycopy(array, 0, newArray, 0, oldCap);
}
}
6.5 堆结构可视化
graph TD
subgraph "PriorityBlockingQueue 堆结构"
A["索引0: 1 (堆顶-最小值)"] --> B["索引1: 3"]
A --> C["索引2: 2"]
B --> D["索引3: 7"]
B --> E["索引4: 5"]
C --> F["索引5: 4"]
C --> G["索引6: 6"]
D --> H["索引7: 9"]
D --> I["索引8: 8"]
end
subgraph "堆操作流程"
J["插入元素"] --> K["添加到数组末尾"]
K --> L["向上调整(siftUp)"]
L --> M["维护堆性质"]
N["删除元素"] --> O["移除堆顶"]
O --> P["末尾元素移到堆顶"]
P --> Q["向下调整(siftDown)"]
Q --> R["维护堆性质"]
end
6.6 PriorityBlockingQueue特性总结
- 无界容量:理论上无容量限制,动态扩容
- 优先级排序:基于二叉堆实现,支持自然排序和自定义比较器
- 单锁设计:使用一个ReentrantLock保护所有操作
- 扩容优化:使用自旋锁避免多线程同时扩容
- 不支持null:不允许插入null元素
- 非FIFO:按优先级出队,不是先进先出
7. SynchronousQueue 源码解析
7.1 核心设计理念
从项目源码 SynchronousQueue.java
中可以看到其独特的设计:
/**
* 同步队列 - 没有内部容量的阻塞队列
* 每个插入操作必须等待另一个线程的移除操作,反之亦然
* 特点:零容量、直接传递、支持公平和非公平模式
*/
public class SynchronousQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
// ========== 核心字段 ==========
/**
* 传输器 - 实际执行put/take操作的核心组件
* 根据公平性选择不同的实现:
* - 公平模式:TransferQueue (FIFO)
* - 非公平模式:TransferStack (LIFO)
*/
private transient volatile Transferer<E> transferer;
/**
* CPU数量,用于自旋优化
*/
static final int NCPUS = Runtime.getRuntime().availableProcessors();
/**
* 在阻塞前的自旋次数
* 多核系统下进行自旋优化
*/
static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;
/**
* 无超时操作的自旋次数
*/
static final int maxUntimedSpins = maxTimedSpins * 16;
/**
* 自旋时间阈值(纳秒)
* 超过此时间才进行自旋
*/
static final long spinForTimeoutThreshold = 1000L;
}
7.2 构造方法分析
/**
* 创建非公平模式的SynchronousQueue
* 默认使用LIFO顺序(栈结构)
*/
public SynchronousQueue() {
this(false);
}
/**
* 创建指定公平性的SynchronousQueue
* @param fair true表示公平模式(FIFO),false表示非公平模式(LIFO)
*/
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}
7.3 核心抽象类 - Transferer
/**
* 传输器抽象类
* 定义了put/take操作的统一接口
*/
abstract static class Transferer<E> {
/**
* 执行put或take操作
* @param e 如果非null,表示put操作;如果null,表示take操作
* @param timed 是否有超时限制
* @param nanos 超时时间(纳秒)
* @return put操作返回传递的元素,take操作返回接收的元素
* 如果被中断或超时,返回null
*/
abstract E transfer(E e, boolean timed, long nanos);
}
7.4 非公平模式 - TransferStack
/**
* 非公平传输器 - 基于栈的LIFO实现
* 后进先出,性能更好但可能导致饥饿
*/
static final class TransferStack<E> extends Transferer<E> {
// ========== 节点类型常量 ==========
/** 请求数据的节点(take操作) */
static final int REQUEST = 0;
/** 提供数据的节点(put操作) */
static final int DATA = 1;
/** 正在匹配的节点 */
static final int FULFILLING = 2;
/** 检查节点是否为匹配模式 */
static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; }
/**
* 栈节点定义
*/
static final class SNode {
volatile SNode next; // 下一个节点
volatile SNode match; // 匹配的节点
volatile Thread waiter; // 等待的线程
Object item; // 数据项
int mode; // 节点模式
SNode(Object item) {
this.item = item;
}
/**
* 尝试CAS设置next指针
*/
boolean casNext(SNode cmp, SNode val) {
return cmp == next && SNEXT.compareAndSet(this, cmp, val);
}
/**
* 尝试匹配当前节点
* @param s 要匹配的节点
* @return 匹配成功返回true
*/
boolean tryMatch(SNode s) {
if (match == null &&
SMATCH.compareAndSet(this, null, s)) {
Thread w = waiter;
if (w != null) { // 唤醒等待线程
waiter = null;
LockSupport.unpark(w);
}
return true;
}
return match == s;
}
/**
* 取消节点(中断或超时时调用)
*/
void tryCancel() {
SMATCH.compareAndSet(this, null, this);
}
/**
* 检查节点是否已取消
*/
boolean isCancelled() {
return match == this;
}
}
/** 栈顶指针 */
volatile SNode head;
/**
* CAS设置栈顶
*/
boolean casHead(SNode h, SNode nh) {
return h == head && SHEAD.compareAndSet(this, h, nh);
}
7.5 TransferStack的transfer方法
/**
* TransferStack的核心传输方法
*/
@SuppressWarnings("unchecked")
E transfer(E e, boolean timed, long nanos) {
SNode s = null; // 当前节点
int mode = (e == null) ? REQUEST : DATA;
for (;;) {
SNode h = head;
// 情况1:栈为空或栈顶节点模式相同
if (h == null || h.mode == mode) {
// 超时检查
if (timed && nanos <= 0L) {
if (h != null && h.isCancelled())
casHead(h, h.next); // 清理取消的节点
else
return null; // 超时返回
}
// 创建新节点并压入栈
else if (casHead(h, s = snode(s, e, h, mode))) {
SNode m = awaitFulfill(s, timed, nanos);
if (m == s) { // 被取消
clean(s);
return null;
}
// 清理栈顶的匹配节点对
if ((h = head) != null && h.next == s)
casHead(h, s.next);
return (E) ((mode == REQUEST) ? m.item : s.item);
}
}
// 情况2:栈顶是FULFILLING模式(正在匹配)
else if (!isFulfilling(h.mode)) {
// 检查是否已取消
if (h.isCancelled())
casHead(h, h.next);
// 尝试匹配栈顶节点
else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
for (;;) {
SNode m = s.next;
if (m == null) { // 匹配的节点消失了
casHead(s, null);
s = null;
break;
}
SNode mn = m.next;
// 尝试匹配
if (m.tryMatch(s)) {
casHead(s, mn);
return (E) ((mode == REQUEST) ? m.item : s.item);
} else {
s.casNext(m, mn); // 匹配失败,移除m
}
}
}
}
// 情况3:帮助其他线程完成匹配
else {
SNode m = h.next;
if (m == null)
casHead(h, null);
else {
SNode mn = m.next;
if (m.tryMatch(h))
casHead(h, mn);
else
h.casNext(m, mn);
}
}
}
}
/**
* 等待匹配完成
*/
SNode awaitFulfill(SNode s, boolean timed, long nanos) {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
int spins = shouldSpin(s) ?
(timed ? maxTimedSpins : maxUntimedSpins) : 0;
for (;;) {
// 检查中断
if (w.isInterrupted())
s.tryCancel();
SNode m = s.match;
if (m != null)
return m;
// 超时检查
if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
s.tryCancel();
continue;
}
}
// 自旋等待
if (spins > 0) {
spins = shouldSpin(s) ? (spins - 1) : 0;
}
// 设置等待线程
else if (s.waiter == null) {
s.waiter = w;
}
// 阻塞等待
else if (!timed) {
LockSupport.park(this);
}
else if (nanos > spinForTimeoutThreshold) {
LockSupport.parkNanos(this, nanos);
}
}
}
7.6 公平模式 - TransferQueue
/**
* 公平传输器 - 基于队列的FIFO实现
* 先进先出,保证公平性但性能略低
*/
static final class TransferQueue<E> extends Transferer<E> {
/**
* 队列节点定义
*/
static final class QNode {
volatile QNode next; // 下一个节点
volatile Object item; // 数据项
volatile Thread waiter; // 等待的线程
final boolean isData; // 是否为数据节点
QNode(Object item, boolean isData) {
this.item = item;
this.isData = isData;
}
/**
* CAS设置next指针
*/
boolean casNext(QNode cmp, QNode val) {
return next == cmp && QNEXT.compareAndSet(this, cmp, val);
}
/**
* CAS设置item
*/
boolean casItem(Object cmp, Object val) {
return item == cmp && QITEM.compareAndSet(this, cmp, val);
}
/**
* 取消节点
*/
void tryCancel(Object cmp) {
QITEM.compareAndSet(this, cmp, this);
}
/**
* 检查是否已取消
*/
boolean isCancelled() {
return item == this;
}
/**
* 检查是否为已知的数据节点
*/
boolean isOffList() {
return next == this;
}
}
/** 队列头指针 */
transient volatile QNode head;
/** 队列尾指针 */
transient volatile QNode tail;
/**
* 清理队列中的取消节点
*/
transient volatile QNode cleanMe;
TransferQueue() {
QNode h = new QNode(null, false); // 虚拟头节点
head = h;
tail = h;
}
/**
* TransferQueue的核心传输方法
*/
@SuppressWarnings("unchecked")
E transfer(E e, boolean timed, long nanos) {
QNode s = null;
boolean isData = (e != null);
for (;;) {
QNode t = tail;
QNode h = head;
if (t == null || h == null) // 未初始化
continue;
// 队列为空或尾节点模式相同
if (h == t || t.isData == isData) {
QNode tn = t.next;
if (t != tail) // 尾指针不一致,重试
continue;
if (tn != null) { // 尾指针落后,推进
advanceTail(t, tn);
continue;
}
if (timed && nanos <= 0L) // 超时检查
return null;
if (s == null)
s = new QNode(e, isData);
if (!t.casNext(null, s)) // 链接失败,重试
continue;
advanceTail(t, s); // 推进尾指针
Object x = awaitFulfill(s, e, timed, nanos);
if (x == s) { // 等待被取消
clean(t, s);
return null;
}
if (!s.isOffList()) { // 节点未出队
advanceHead(t, s);
if (x != null)
s.item = s;
s.waiter = null;
}
return (x != null) ? (E)x : e;
}
// 队列中有互补节点,尝试匹配
else {
QNode m = h.next; // 头节点的下一个
if (t != tail || m == null || h != head)
continue; // 不一致,重试
Object x = m.item;
if (isData == (x != null) || // 模式不匹配
x == m || // 已取消
!m.casItem(x, e)) { // CAS失败
advanceHead(h, m); // 推进头指针
continue;
}
advanceHead(h, m); // 匹配成功,推进头指针
LockSupport.unpark(m.waiter); // 唤醒等待线程
return (x != null) ? (E)x : e;
}
}
}
/**
* 等待匹配完成
*/
Object awaitFulfill(QNode s, Object e, boolean timed, long nanos) {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
int spins = (head.next == s) ?
(timed ? maxTimedSpins : maxUntimedSpins) : 0;
for (;;) {
if (w.isInterrupted())
s.tryCancel(e);
Object x = s.item;
if (x != e)
return x;
if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
s.tryCancel(e);
continue;
}
}
if (spins > 0) {
--spins;
}
else if (s.waiter == null) {
s.waiter = w;
}
else if (!timed) {
LockSupport.park(this);
}
else if (nanos > spinForTimeoutThreshold) {
LockSupport.parkNanos(this, nanos);
}
}
}
}
7.7 核心操作方法
/**
* 插入元素 - 必须等待消费者线程
*/
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
if (transferer.transfer(e, false, 0) == null) {
Thread.interrupted();
throw new InterruptedException();
}
}
/**
* 非阻塞插入 - 如果没有等待的消费者立即返回false
*/
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
return transferer.transfer(e, true, 0) != null;
}
/**
* 超时插入
*/
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
if (transferer.transfer(e, true, unit.toNanos(timeout)) != null)
return true;
if (!Thread.interrupted())
return false;
throw new InterruptedException();
}
/**
* 获取元素 - 必须等待生产者线程
*/
public E take() throws InterruptedException {
E e = transferer.transfer(null, false, 0);
if (e != null)
return e;
Thread.interrupted();
throw new InterruptedException();
}
/**
* 非阻塞获取 - 如果没有等待的生产者立即返回null
*/
public E poll() {
return transferer.transfer(null, true, 0);
}
/**
* 超时获取
*/
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
E e = transferer.transfer(null, true, unit.toNanos(timeout));
if (e != null || !Thread.interrupted())
return e;
throw new InterruptedException();
}
/**
* 队列大小始终为0
*/
public int size() {
return 0;
}
/**
* 队列始终为空
*/
public boolean isEmpty() {
return true;
}
7.8 SynchronousQueue工作流程图
sequenceDiagram
participant P as Producer
participant SQ as SynchronousQueue
participant C as Consumer
Note over P,C: 场景1:生产者先到达
P->>SQ: put(item)
Note over SQ: 创建DATA节点,等待匹配
C->>SQ: take()
Note over SQ: 匹配成功,直接传递
SQ->>C: 返回item
SQ->>P: put操作完成
Note over P,C: 场景2:消费者先到达
C->>SQ: take()
Note over SQ: 创建REQUEST节点,等待匹配
P->>SQ: put(item)
Note over SQ: 匹配成功,直接传递
SQ->>C: 返回item
SQ->>P: put操作完成
Note over P,C: 场景3:非阻塞操作
P->>SQ: offer(item)
Note over SQ: 没有等待的消费者
SQ->>P: 返回false
7.9 SynchronousQueue特性总结
- 零容量:不存储任何元素,每个操作必须等待匹配
- 直接传递:生产者直接将元素传递给消费者
- 双模式:支持公平(FIFO)和非公平(LIFO)模式
- 高性能:无锁算法,使用CAS操作
- 自旋优化:多核环境下使用自旋减少上下文切换
- 适用场景:线程池、生产者-消费者直接交换
8. LinkedBlockingDeque 源码解析
8.1 核心数据结构
从项目源码 LinkedBlockingDeque.java
中可以看到其双端队列的实现:
/**
* 基于链表的双端阻塞队列
* 支持从队头和队尾进行插入和删除操作
* 特点:可选有界、双端操作、单锁设计
*/
public class LinkedBlockingDeque<E>
extends AbstractQueue<E>
implements BlockingDeque<E>, java.io.Serializable {
// ========== 核心字段 ==========
/**
* 双向链表节点
*/
static final class Node<E> {
/**
* 节点存储的元素
* 如果为null且节点未被移除,表示这是一个占位符节点
*/
E item;
/**
* 前驱节点指针
* 如果为null,表示这是第一个节点
*/
Node<E> prev;
/**
* 后继节点指针
* 如果为null,表示这是最后一个节点
*/
Node<E> next;
Node(E x) {
item = x;
}
}
/**
* 队列头节点指针
* 不变性:first.prev == null
*/
transient Node<E> first;
/**
* 队列尾节点指针
* 不变性:last.next == null
*/
transient Node<E> last;
/** 队列中元素的数量 */
private transient int count;
/** 队列的最大容量 */
private final int capacity;
/** 保护所有操作的锁 */
final ReentrantLock lock = new ReentrantLock();
/** 等待take操作的条件队列 */
private final Condition notEmpty = lock.newCondition();
/** 等待put操作的条件队列 */
private final Condition notFull = lock.newCondition();
}
8.2 构造方法分析
/**
* 创建无界LinkedBlockingDeque
*/
public LinkedBlockingDeque() {
this(Integer.MAX_VALUE);
}
/**
* 创建指定容量的LinkedBlockingDeque
*/
public LinkedBlockingDeque(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
}
/**
* 创建包含指定集合元素的LinkedBlockingDeque
*/
public LinkedBlockingDeque(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
final ReentrantLock lock = this.lock;
lock.lock(); // 确保可见性,虽然构造时不需要
try {
for (E e : c) {
if (e == null)
throw new NullPointerException();
if (!linkLast(new Node<E>(e)))
throw new IllegalStateException("Deque full");
}
} finally {
lock.unlock();
}
}
8.3 核心操作方法
8.3.1 队头插入操作
/**
* 在队头插入元素 - 阻塞版本
*/
public void putFirst(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
while (!linkFirst(node)) // 队列满时等待
notFull.await();
} finally {
lock.unlock();
}
}
/**
* 在队头插入元素 - 非阻塞版本
*/
public boolean offerFirst(E e) {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
return linkFirst(node);
} finally {
lock.unlock();
}
}
/**
* 链接节点到队头
* 调用前必须持有锁
*/
private boolean linkFirst(Node<E> node) {
if (count >= capacity) // 队列已满
return false;
Node<E> f = first;
node.next = f;
first = node;
if (last == null) // 队列原本为空
last = node;
else
f.prev = node;
++count;
notEmpty.signal(); // 唤醒等待的消费者
return true;
}
8.3.2 队尾插入操作
/**
* 在队尾插入元素 - 阻塞版本
*/
public void putLast(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
while (!linkLast(node)) // 队列满时等待
notFull.await();
} finally {
lock.unlock();
}
}
/**
* 在队尾插入元素 - 非阻塞版本
*/
public boolean offerLast(E e) {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
return linkLast(node);
} finally {
lock.unlock();
}
}
/**
* 链接节点到队尾
* 调用前必须持有锁
*/
private boolean linkLast(Node<E> node) {
if (count >= capacity) // 队列已满
return false;
Node<E> l = last;
node.prev = l;
last = node;
if (first == null) // 队列原本为空
first = node;
else
l.next = node;
++count;
notEmpty.signal(); // 唤醒等待的消费者
return true;
}
8.3.3 队头删除操作
/**
* 从队头获取元素 - 阻塞版本
*/
public E takeFirst() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
E x;
while ((x = unlinkFirst()) == null) // 队列空时等待
notEmpty.await();
return x;
} finally {
lock.unlock();
}
}
/**
* 从队头获取元素 - 非阻塞版本
*/
public E pollFirst() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return unlinkFirst();
} finally {
lock.unlock();
}
}
/**
* 移除队头节点
* 调用前必须持有锁
*/
private E unlinkFirst() {
Node<E> f = first;
if (f == null) // 队列为空
return null;
Node<E> n = f.next;
E item = f.item;
f.item = null;
f.next = f; // 帮助GC
first = n;
if (n == null) // 队列变为空
last = null;
else
n.prev = null;
--count;
notFull.signal(); // 唤醒等待的生产者
return item;
}
8.3.4 队尾删除操作
/**
* 从队尾获取元素 - 阻塞版本
*/
public E takeLast() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
E x;
while ((x = unlinkLast()) == null) // 队列空时等待
notEmpty.await();
return x;
} finally {
lock.unlock();
}
}
/**
* 从队尾获取元素 - 非阻塞版本
*/
public E pollLast() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return unlinkLast();
} finally {
lock.unlock();
}
}
/**
* 移除队尾节点
* 调用前必须持有锁
*/
private E unlinkLast() {
Node<E> l = last;
if (l == null) // 队列为空
return null;
Node<E> p = l.prev;
E item = l.item;
l.item = null;
l.prev = l; // 帮助GC
last = p;
if (p == null) // 队列变为空
first = null;
else
p.next = null;
--count;
notFull.signal(); // 唤醒等待的生产者
return item;
}
8.4 LinkedBlockingDeque结构图
graph LR
subgraph "LinkedBlockingDeque 双向链表结构"
A["first"] --> B["Node1"]
B --> C["Node2"]
C --> D["Node3"]
D --> E["last"]
B -.-> A
C -.-> B
D -.-> C
E -.-> D
end
subgraph "双端操作"
F["putFirst/offerFirst"] --> A
G["takeFirst/pollFirst"] --> A
H["putLast/offerLast"] --> E
I["takeLast/pollLast"] --> E
end
8.5 LinkedBlockingDeque特性总结
- 双端操作:支持从队头和队尾进行插入和删除
- 可选有界:可以指定容量,默认无界
- 单锁设计:使用一个ReentrantLock保护所有操作
- 双向链表:基于双向链表实现,支持高效的双端操作
- FIFO/LIFO:可以作为队列(FIFO)或栈(LIFO)使用
- 线程安全:所有操作都是线程安全的
9. 阻塞队列对比分析
9.1 特性对比表
特性 | ArrayBlockingQueue | LinkedBlockingQueue | PriorityBlockingQueue | SynchronousQueue | LinkedBlockingDeque |
---|---|---|---|---|---|
数据结构 | 环形数组 | 单向链表 | 二叉堆 | 栈/队列 | 双向链表 |
容量限制 | 有界 | 可选有界 | 无界 | 零容量 | 可选有界 |
锁机制 | 单锁 | 双锁 | 单锁+自旋锁 | 无锁(CAS) | 单锁 |
排序方式 | FIFO | FIFO | 优先级 | 直接传递 | FIFO/LIFO |
公平性 | 可选 | 否 | 否 | 可选 | 否 |
内存开销 | 低 | 中等 | 中等 | 最低 | 中等 |
吞吐量 | 中等 | 高 | 中等 | 最高 | 中等 |
适用场景 | 固定容量缓冲 | 生产者-消费者 | 任务调度 | 线程池 | 双端操作 |
图例说明:
- 🔵 ArrayBlockingQueue:固定容量,单锁设计
- 🟢 LinkedBlockingQueue:可选容量,双锁设计
- 🟡 PriorityBlockingQueue:优先级排序,无界容量
- 🔴 SynchronousQueue:零容量,直接传递
- 🟣 LinkedBlockingDeque:双端操作,单锁设计
10. 最佳实践与选择指南
10.1 选择决策树
flowchart TD
A["需要阻塞队列"] --> B{"是否需要优先级排序?"}
B -->|是| C["PriorityBlockingQueue"]
B -->|否| D{"是否需要直接传递?"}
D -->|是| E["SynchronousQueue"]
D -->|否| F{"是否需要双端操作?"}
F -->|是| G["LinkedBlockingDeque"]
F -->|否| H{"容量是否固定?"}
H -->|是| I{"是否需要公平性?"}
I -->|是| J["ArrayBlockingQueue(fair)"]
I -->|否| K["ArrayBlockingQueue"]
H -->|否| L{"是否需要高并发?"}
L -->|是| M["LinkedBlockingQueue"]
L -->|否| N["ArrayBlockingQueue"]
10.2 使用建议
10.2.1 ArrayBlockingQueue
- 适用场景:固定大小的缓冲区、内存敏感的应用
- 优势:内存占用少、缓存友好
- 注意事项:单锁可能成为瓶颈
10.2.2 LinkedBlockingQueue
- 适用场景:生产者-消费者模式、高并发场景
- 优势:双锁设计、高吞吐量
- 注意事项:内存开销较大
10.2.3 PriorityBlockingQueue
- 适用场景:任务调度、优先级处理
- 优势:自动排序、无界容量
- 注意事项:不保证同优先级元素的顺序
10.2.4 SynchronousQueue
- 适用场景:线程池、直接交换
- 优势:零延迟、高性能
- 注意事项:必须有配对的操作
10.2.5 LinkedBlockingDeque
- 适用场景:工作窃取、双端操作
- 优势:灵活的操作方式
- 注意事项:单锁限制并发性
10.3 性能调优建议
- 容量设置:根据实际需求设置合适的容量
- 公平性权衡:公平性会降低性能,按需选择
- 批量操作:使用drainTo等批量操作提高效率
- 监控指标:关注队列大小、等待时间等指标
- 异常处理:正确处理中断和超时异常
总结
本文深入分析了Java并发包中的五种主要阻塞队列实现,从源码层面解析了它们的设计原理、实现机制和性能特点。每种阻塞队列都有其独特的适用场景:
- ArrayBlockingQueue:适合固定容量的缓冲场景
- LinkedBlockingQueue:适合高并发的生产者-消费者模式
- PriorityBlockingQueue:适合需要优先级排序的任务调度
- SynchronousQueue:适合直接传递的高性能场景
- LinkedBlockingDeque:适合需要双端操作的复杂场景
理解这些队列的内部实现有助于在实际开发中做出正确的选择,并能够针对性地进行性能优化。