concurrentlinkedqueue 是基于 cas、volatile 和自旋重试的无锁单向链表队列,不依赖 synchronized 或 reentrantlock,通过 casnext/casitem 原子操作实现线程安全,支持高并发、低延迟、非阻塞 fifo 操作。

ConcurrentLinkedQueue 用无锁 CAS 实现高效单向队列,核心在于不依赖 synchronized 或 ReentrantLock,而是靠原子操作 + volatile + 自旋重试,在高并发下避免线程挂起和锁竞争,从而获得低延迟、高吞吐的表现。
底层是单向链表,节点字段全用 volatile 修饰
每个 Node 包含 item 和 next,两者都被声明为 volatile。这确保任意线程对 next 的更新能立即被其他线程看到,防止因 CPU 缓存不一致读到过期指针;item 设为 volatile 还支持“懒删除”——出队成功后将其设为 null,作为该节点已被消费的标记。
- 初始化时 head 和 tail 都指向一个 item 为 null 的哨兵节点
- 新元素总插入 tail 后面,出队总从 head 后继节点取值
- head/tail 本身也是 volatile 类型,保证多线程可见性
CAS 操作驱动所有关键步骤
入队(offer)和出队(poll)都依赖 Unsafe 提供的 casItem 和 casNext 方法。比如入队时,先尝试用 CAS 将当前 tail 的 next 指向新节点;若失败(说明 tail 已被其他线程更新),就重新读取 tail 再试——这个过程是自旋,不阻塞也不挂起线程。
- casNext(oldNext, newNode):只有当 next 字段当前值等于 oldNext 时,才把 next 更新为 newNode
- casItem(oldItem, null):出队时将已取出节点的 item 设为 null,表示逻辑删除
- 所有 CAS 失败都会触发重试循环,直到成功或确认操作不可行(如 poll 时队列真为空)
延迟更新 head/tail + 懒删除提升性能
为了减少 CAS 竞争,head 和 tail 并不每次操作都立即更新。比如 tail 可能滞后于实际尾节点几个位置,只要不影响 FIFO 语义即可;同样,head 也可能指向已出队的哨兵节点,需跳过 item == null 的节点才能找到有效头。
- 这种“松弛”策略降低了 CAS 冲突概率,尤其在连续入队场景下效果明显
- 懒删除让出队不真正断开链表,只置空 item,后续由其他线程在遍历或清理时顺带跳过
- 迭代器不加锁,看到的是弱一致性快照,不会抛 ConcurrentModificationException
非阻塞特性决定它的适用边界
它永远不阻塞线程:offer 总返回 true,poll 在空时直接返回 null。这意味着你不能靠它做“等待有数据再处理”的逻辑,需要配合轮询或结合其他同步机制(如 CountDownLatch、外部信号)。
- 适合生产者-消费者速率接近、且允许“忙等”或上层有重试机制的场景
- 不适合要求强一致性、严格实时响应或低 CPU 占用的系统
- 内存不受限但实际容量仍受堆大小制约,无界 ≠ 无限
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











