LinkedBlockingQueue 就像一条 “允许双端同时操作的传送带” ,生产者在一端放东西,消费者在另一端取东西,两边可以同时工作互不干扰。它是 Java 中线程安全的高性能阻塞队列,专为高并发场景设计。
一、核心特点
-
基于链表实现
- 元素存储在链表的节点中,可以动态扩展(默认无界,但建议设置容量避免内存耗尽)。
- 示例:
new LinkedBlockingQueue<>(100);表示最多容纳100个元素。
-
双锁机制
- 生产者锁(
putLock):控制入队操作。 - 消费者锁(
takeLock):控制出队操作。 - 优势:生产者和消费者可以同时操作,互不阻塞,提高并发性能。
- 生产者锁(
-
阻塞行为
- 队列满时:生产者调用
put()会被阻塞,直到有空位。 - 队列空时:消费者调用
take()会被阻塞,直到有新元素。 - 非阻塞方法:
offer()和poll()直接返回成功与否,不等待。
- 队列满时:生产者调用
二、与 ArrayBlockingQueue 对比
| 对比项 | LinkedBlockingQueue | ArrayBlockingQueue |
|---|---|---|
| 底层结构 | 链表(动态扩展) | 数组(固定容量) |
| 锁机制 | 双锁(生产消费并行) | 单锁(生产消费互斥) |
| 默认容量 | 无界(Integer.MAX_VALUE) | 必须指定容量 |
| 内存占用 | 更高(每个元素多两个指针) | 更低(连续内存,无指针开销) |
| 吞吐量 | 更高(适合高并发) | 较低(单锁竞争) |
三、适用场景
-
高并发生产者-消费者
- 比如电商秒杀活动,大量用户同时下单(生产者)和系统处理订单(消费者)。
BlockingQueue<Order> orderQueue = new LinkedBlockingQueue<>(1000); -
任务调度池
-
线程池(如
Executors.newFixedThreadPool)默认使用无界LinkedBlockingQueue。
ExecutorService executor = Executors.newFixedThreadPool(4); // 内部任务队列:new LinkedBlockingQueue<>() -
-
流式数据处理
- 数据流水线处理,如日志收集后批量写入数据库。
四、工作原理
-
入队(生产者)
-
获取
putLock,检查队列是否已满:- 如果未满 → 插入新节点到链表尾部。
- 如果已满 → 阻塞等待,直到消费者取走元素唤醒。
-
释放
putLock,并通知消费者队列非空。
-
-
出队(消费者)
-
获取
takeLock,检查队列是否为空:- 如果不空 → 移除链表头部节点并返回。
- 如果空 → 阻塞等待,直到生产者放入元素唤醒。
-
释放
takeLock,并通知生产者队列有空位。
-
五、代码示例
public class ProducerConsumerExample {
public static void main(String[] args) {
BlockingQueue<String> queue = new LinkedBlockingQueue<>(5);
// 生产者
new Thread(() -> {
try {
queue.put("任务1");
queue.put("任务2");
queue.put("任务3"); // 队列满时阻塞
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// 消费者
new Thread(() -> {
try {
String task = queue.take(); // 队列空时阻塞
System.out.println("处理任务:" + task);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
}
六、注意事项
-
避免无界队列:
- 默认无界队列可能导致内存溢出(OOM),务必设置合理容量。
-
平衡生产消费速度:
- 如果生产者远快于消费者,即使队列有界也可能积压,需监控队列大小。
-
优先用
offer()和poll():- 非阻塞方法更安全,避免线程长时间阻塞。
七、总结
LinkedBlockingQueue 是高并发场景的利器:
- 优势:双锁机制提升吞吐量,动态扩展更灵活。
- 注意:内存开销略大,需合理设置容量。
适用场景:
- 高并发且生产消费操作频繁。
- 需要灵活扩展队列容量(但需谨慎无界风险)。
口诀:
「链表队列双锁强,生产消费两不忙
高并发下吞吐高,内存稍大也无妨
默认无界有隐患,设置容量保平安!」