concurrentlinkedqueue 是 java 中基于链表的无锁、线程安全 fifo 队列,通过 cas 实现高并发低延迟,不支持 null,弱一致性迭代器,适用于日志缓冲等吞吐优先场景。

ConcurrentLinkedQueue 是 Java 并发包(java.util.concurrent)中一个基于链表实现的无锁(lock-free)、线程安全的队列,适用于高并发、低延迟场景。它不依赖 synchronized 或 ReentrantLock,而是通过 CAS(Compare-and-Swap)原子操作实现多线程安全,避免了锁竞争带来的性能损耗和阻塞风险。
核心特性与适用场景
ConcurrentLinkedQueue 是一个非阻塞、无界、FIFO 队列,支持以下关键行为:
- 所有操作(offer、poll、peek)都是无锁且线程安全的,底层使用 UNSAFE.compareAndSet 操作节点指针
- 不支持 null 元素,插入或读取 null 会抛出 NullPointerException
- 弱一致性迭代器:遍历时可能看不到部分已入队元素,也不反映实时结构变化,但不会抛 ConcurrentModificationException
- 适合“生产者-消费者”解耦明显、允许短暂不一致、吞吐优先于强实时性的场景(如日志缓冲、事件总线、异步任务分发)
基本用法与典型操作
声明和初始化简单直接,无需指定容量:
ConcurrentLinkedQueue
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
常用方法及注意事项:
- offer(E e):尾部插入,成功返回 true;e 为 null 抛异常;永远不阻塞、不失败(因无界)
- poll():头部移除并返回元素;队列空时返回 null(不是阻塞等待)
- peek():仅查看头元素,不移除;空队列返回 null
- isEmpty() / size():isEmpty 可靠;size() 是遍历计数,高并发下可能不准,不建议用于条件判断(如 while (!queue.isEmpty()) poll() 是安全的,但 if (queue.size() > 10) 不可靠)
高并发下的正确使用模式
避免常见误用,发挥其无锁优势:
- 不要用 size() 控制流量或触发动作,改用原子计数器(如 AtomicInteger)或信号量配合业务逻辑
- 批量消费推荐“循环 poll + 空检查”,而非预估大小再循环,例如:
String task;
while ((task = queue.poll()) != null) {
// 处理 task
} - 若需阻塞语义(如消费者等新任务),应组合使用其他工具(如 LinkedBlockingQueue),ConcurrentLinkedQueue 本身不提供 take() 或 put() 这类阻塞方法
- 避免在 offer/poll 中执行耗时操作(如 I/O、复杂计算),否则会拉长 CAS 尝试窗口,降低整体吞吐
与其它并发队列对比要点
选型时需结合实际需求权衡:
- vs LinkedBlockingQueue:后者基于锁 + 条件队列,支持阻塞、可选容量限制、强一致性,但高争用下易出现线程挂起/唤醒开销
- vs ArrayBlockingQueue:有界、基于数组、锁实现,内存连续、缓存友好,但扩容不可行、吞吐受限于锁粒度
- vs BlockingDeque(如 LinkedBlockingDeque):支持双端操作和阻塞,功能更丰富,但同步成本更高
- ConcurrentLinkedQueue 的优势在于纯无锁、高吞吐、低延迟,代价是弱一致性、无界风险(需业务控制生产速率)、不支持阻塞
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










