在 Java 中,Queue 接口的实现类可按阻塞特性和数据结构分为四大类,每类都有独特的并发控制机制和适用场景。以下是具体分类及实现类解析:
一、阻塞队列(BlockingQueue):线程安全的阻塞等待机制
阻塞队列在队列满/空时会阻塞线程,直到条件满足,是生产者-消费者模型的核心组件。其核心特性是提供 put()(阻塞入队)和 take()(阻塞出队)方法。
1. ArrayBlockingQueue:基于数组的有界阻塞队列
- 特点:
- 有界性:创建时必须指定容量(如
new ArrayBlockingQueue<>(100)),数组大小固定。 - 锁机制:使用单把 ReentrantLock 控制入队和出队,支持公平/非公平模式(默认非公平)。
- 性能:数组结构内存紧凑,随机访问快,但因单锁导致生产者-消费者无法完全并行。
- 有界性:创建时必须指定容量(如
- 应用场景:
- 固定大小的资源池(如数据库连接池)、限流场景(防止内存溢出)。
- 示例:摄像头采集系统中,多线程采集图片后通过
ArrayBlockingQueue传递给存储线程。
2. LinkedBlockingQueue:基于链表的可选有界阻塞队列
- 特点:
- 容量灵活:默认容量为
Integer.MAX_VALUE(无界),也可指定容量(有界)。 - 锁分离:生产者使用
putLock,消费者使用takeLock,支持更高并发吞吐量。 - 内存开销:链表节点动态分配,可能产生较多 GC 压力。
- 容量灵活:默认容量为
- 应用场景:
- 高吞吐量的生产者-消费者系统(如日志收集、任务调度),需注意无界模式下的内存溢出风险。
3. PriorityBlockingQueue:基于优先级的无界阻塞队列
- 特点:
- 无界性:容量理论上无限(受内存限制),元素按自然顺序或自定义
Comparator排序。 - 实现:底层为二叉堆,通过单锁保证线程安全,入队/出队时间复杂度为 O(log n)。
- 无界性:容量理论上无限(受内存限制),元素按自然顺序或自定义
- 应用场景:
- 任务调度系统(如按优先级处理订单)、延迟任务执行。
4. DelayQueue:延迟触发的无界阻塞队列
- 特点:
- 延迟机制:元素必须实现
Delayed接口,只有到期元素才能被取出。 - 实现:基于优先级队列,通过单锁控制,适用于定时任务(如缓存过期清理)。
- 延迟机制:元素必须实现
- 应用场景:
- 定时任务调度(如订单超时取消)、会话过期管理。
5. SynchronousQueue:零容量的同步移交队列
- 特点:
- 无缓冲:容量为 0,生产者需等待消费者取走元素(直接移交数据)。
- 高性能:无锁设计(CAS 操作),适合线程间低延迟数据传递。
- 应用场景:
Executors.newCachedThreadPool()的任务队列,实现线程复用。
6. LinkedBlockingDeque:双端阻塞队列
- 特点:
- 双向操作:支持从头部/尾部入队/出队(如
addFirst()/takeLast()),可作为队列或栈使用。 - 锁分离:头/尾操作使用独立锁,并发性能优于
LinkedBlockingQueue。
- 双向操作:支持从头部/尾部入队/出队(如
- 应用场景:
- 工作窃取算法(Worker Stealing)、同时需要 FIFO 和 LIFO 操作的场景。
二、非阻塞队列:无锁的 CAS 并发控制
非阻塞队列通过 CAS 操作实现线程安全,不会阻塞线程,适合高并发、允许短暂忙等的场景。
1. ConcurrentLinkedQueue:基于链表的无界非阻塞队列
- 特点:
- 无锁实现:通过 CAS 操作更新头/尾节点,避免锁竞争,吞吐量极高。
- 无界性:理论容量无限,元素通过单向链表存储。
- 弱一致性:迭代器可能返回旧数据,但不影响整体可用性。
- 应用场景:
- 高并发日志收集、分布式系统中的任务分发(如消息队列客户端缓存)。
2. ConcurrentLinkedDeque:双端无界非阻塞队列
- 特点:
- 双向操作:支持从头部/尾部 CAS 操作,功能类似
LinkedBlockingDeque但无锁。
- 双向操作:支持从头部/尾部 CAS 操作,功能类似
- 应用场景:
- 多线程共享的双端任务列表(如 undo/redo 操作栈)。
三、非并发队列:单线程场景的基础实现
非并发队列线程不安全,仅适用于单线程环境,或需手动加锁保证安全。
1. LinkedList(实现 Queue 接口)
- 特点:基于双向链表,支持动态扩容,但无并发控制,多线程下需配合
synchronized使用。 - 应用场景:单线程的任务调度(如本地任务队列)。
2. ArrayDeque:基于数组的双端队列
- 特点:循环数组实现,性能优于
LinkedList,但非线程安全。 - 应用场景:单线程的栈(
push()/pop())或队列操作。
四、优先级队列(PriorityQueue):无序存储,有序输出
- 特点:
- 基于二叉堆实现,元素按优先级排序(自然顺序或自定义比较器),非线程安全。
- 无界性:容量自动扩容,但需注意内存溢出风险。
- 应用场景:
- 单线程环境下的任务优先级排序(如学生成绩排名)。
核心实现类对比表
| 类型 | 实现类 | 数据结构 | 有界性 | 并发控制 | 核心方法 | 典型场景 |
|---|---|---|---|---|---|---|
| 阻塞队列 | ArrayBlockingQueue | 数组 | 有界 | 单锁(ReentrantLock) | put()/take() | 资源池、限流 |
| 阻塞队列 | LinkedBlockingQueue | 链表 | 可选 | 双锁(分离入队/出队) | put()/take() | 高吞吐生产者-消费者系统 |
| 阻塞队列 | PriorityBlockingQueue | 二叉堆 | 无界 | 单锁 | put()/take() | 优先级任务调度 |
| 非阻塞队列 | ConcurrentLinkedQueue | 单向链表 | 无界 | CAS 操作 | offer()/poll() | 高并发日志收集、分布式任务分发 |
| 非并发队列 | LinkedList | 双向链表 | 无界 | 无(需手动同步) | add()/remove() | 单线程任务队列 |
总结与最佳实践
- 高并发阻塞场景:选
LinkedBlockingQueue(双锁高吞吐)或ArrayBlockingQueue(固定容量,内存可控)。 - 高并发非阻塞场景:
ConcurrentLinkedQueue无锁性能最优,适合日志、事件传递。 - 优先级或延迟需求:
PriorityBlockingQueue(优先级)或DelayQueue(定时触发)。 - 单线程场景:
ArrayDeque(栈/队列)或PriorityQueue(排序)更轻量高效。
思考:若需实现一个支持“超时等待+优先级”的队列,能否组合 DelayQueue 和 PriorityBlockingQueue 的特性?(提示:可自定义 Delayed 元素并重写 compareTo() 方法)。