好的,下面给你一个 BlockingQueue(阻塞队列)详解,包含概念、原理、常见实现类和使用场景。
1. 什么是 BlockingQueue?
BlockingQueue
是 Java 并发包(java.util.concurrent
) 提供的一个接口,继承自 Queue
。
它最大的特点是:
- 在队列为空时,从队列中获取元素的操作会 阻塞;
- 在队列已满时,向队列中添加元素的操作也会 阻塞。
这种机制在 生产者-消费者模式 中非常常见,能够高效解决线程同步问题。
2. BlockingQueue 的核心方法
BlockingQueue 提供了 4 类操作方式:
方法类别 | 抛异常 | 特殊值(返回 null/false) | 阻塞等待 | 超时等待 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | —— | —— |
📌 关键点:
put()
→ 队列满时阻塞。take()
→ 队列空时阻塞。
3. 常见实现类
(1)ArrayBlockingQueue
- 基于 数组 的有界阻塞队列(必须指定容量)。
- 按 FIFO(先进先出)顺序存取。
- 适合固定大小队列的场景。
(2)LinkedBlockingQueue
- 基于 链表 的阻塞队列。
- 默认容量是
Integer.MAX_VALUE
(非常大)。 - 插入、删除性能较好。
(3)PriorityBlockingQueue
- 支持优先级排序 的无界阻塞队列。
- 不保证 FIFO,而是根据元素的 优先级 来出队。
(4)DelayQueue
- 带有 延迟时间 的无界阻塞队列。
- 只有 到期元素 才能被取出。
- 常用于 定时任务、缓存过期处理。
(5)SynchronousQueue
- 不存储任何元素 的阻塞队列。
- 每个
put
必须等待一个take
,反之亦然。 - 常用于 任务直接交接。
(6)LinkedTransferQueue
- 基于链表的无界阻塞队列,支持
transfer()
方法:transfer()
会阻塞,直到有消费者取走数据。
4. 使用场景
- 生产者-消费者模式
- 多个生产者线程往队列
put
数据,多个消费者线程从队列take
数据。
- 多个生产者线程往队列
- 线程池
- Java 的
ThreadPoolExecutor
就是用BlockingQueue
来存放任务的。
- Java 的
- 定时任务
- 使用
DelayQueue
实现任务调度。
- 使用
- 限流
SynchronousQueue
配合线程池实现高效限流。
5. 示例代码
import java.util.concurrent.*;
public class BlockingQueueDemo {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(3);
// 生产者线程
new Thread(() -> {
try {
for (int i = 1; i <= 5; i++) {
System.out.println("生产:" + i);
queue.put(i); // 队列满时会阻塞
Thread.sleep(500);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// 消费者线程
new Thread(() -> {
try {
while (true) {
Integer item = queue.take(); // 队列空时会阻塞
System.out.println("消费:" + item);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
运行结果(大致):
生产:1
消费:1
生产:2
生产:3
消费:2
生产:4
消费:3
生产:5
消费:4
消费:5
发表回复