linkedblockingdeque是java并发包中基于链表实现的线程安全有界双端阻塞队列,采用分离锁(headlock/taillock)与条件变量(notempty/notfull)机制支持头尾并发操作,通过volatile修饰的count和节点字段保障读操作可见性与o(1) size()性能,并严格按构造时指定容量限制元素数量。

LinkedBlockingDeque 是 Java 并发包(java.util.concurrent)中提供的一个线程安全的、基于链表实现的有界双端阻塞队列。它通过可重入锁(ReentrantLock)+ 条件变量(Condition)组合实现线程安全与阻塞语义,而非依赖 synchronized 或 CAS 全局锁,兼顾性能与功能完整性。
用 ReentrantLock 保证操作原子性
队列内部维护两个独立的 ReentrantLock:一个用于控制头端(head)操作(如 takeFirst、offerFirst),另一个用于尾端(tail)操作(如 takeLast、offerLast)。这种分离锁设计允许头尾操作并发执行,显著提升吞吐量。每个锁都配套一个 Condition 实例,分别用于 await 空/满状态。
- 所有修改结构的操作(offer/take/poll/peek 等)都必须先获取对应端的锁
- 插入失败时(容量已满),线程在 tailLock 的 notFull 条件上 await;移除失败时(队列为空),在 headLock 的 notEmpty 条件上 await
- 成功插入后唤醒等待消费的线程(signal notEmpty);成功移除后唤醒等待插入的线程(signal notFull)
用 volatile + 链表节点实现无锁读取与安全可见性
虽然写操作加锁,但部分只读方法(如 size()、isEmpty())不加锁,而是依赖 volatile 修饰的 count 字段 和节点 next/prev 的 volatile 声明来保障内存可见性。count 在每次插入/删除时由持有锁的线程原子更新,其他线程读取时能立即看到最新值。
- size() 返回的是 volatile int count,不是遍历链表计算,因此是 O(1) 且线程安全
- 节点的 item、next、prev 均为 volatile,确保多线程下引用变更对其他线程可见
- 注意:size() 返回的值可能只是“某一时刻快照”,不能作为同步判断依据(如 if (size() > 0) poll() 仍可能返回 null)
双端语义与阻塞行为由 API 分层封装
LinkedBlockingDeque 实现了 Deque 接口全部双端操作,并按阻塞策略提供三类方法:
- 抛异常型(addFirst/addLast):容量满时直接抛 IllegalStateException
- 特殊值型(offerFirst/offerLast):满时返回 false,不阻塞
- 阻塞型(putFirst/putLast、takeFirst/takeLast):满/空时分别阻塞,直到条件满足或被中断
这些方法底层统一调用带超时或无超时的 lockInterruptibly + await / signal 逻辑,确保响应中断(InterruptedException)并释放锁资源。
有界性由构造时指定容量严格控制
队列在构造时必须传入正整数 capacity(不可为 Integer.MAX_VALUE,否则退化为无界),内部用该值初始化 count 的上限。所有 offer/put 操作都会检查当前 count 是否已达 capacity,是则拒绝插入。这种显式有界设计避免了内存无限增长风险,也使阻塞行为可预期。
- capacity 在构造后不可更改,属于不可变配置
- 实际可用空间始终 ≤ capacity,即使节点对象本身占用额外内存,队列逻辑长度不会越界
- 与 ArrayBlockingQueue 不同,它不要求预先分配固定数组,更灵活适应动态元素大小
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











