concurrentlinkedqueue 是 java 并发包中基于 cas 和 volatile 实现的无锁、线程安全、无界 fifo 队列,不支持 null 元素,适用于高吞吐、非阻塞场景,但 size() 非实时准确。

ConcurrentLinkedQueue 是 Java 并发包(java.util.concurrent)中提供的一个线程安全、无锁(lock-free)的队列实现,底层基于 CAS(Compare-and-Swap)操作和 volatile 变量,适用于高并发、低竞争场景。它不阻塞线程,也不加 synchronized 或 ReentrantLock,性能通常优于 BlockingQueue 类型(如 LinkedBlockingQueue)在非阻塞需求下。
核心特性与适用场景
ConcurrentLinkedQueue 是一个基于链表的无界线程安全队列,遵循 FIFO 原则。它支持所有标准队列操作(offer、poll、peek),但不支持 null 元素(插入 null 会抛 NullPointerException)。适合以下场景:
- 生产者-消费者模型中无需阻塞等待,消费者可立即返回 null 表示队列为空
- 日志收集、事件缓冲、异步任务分发等对吞吐量敏感、允许“尽力而为”处理的场景
- 避免锁开销或死锁风险,且能接受弱一致性(如 size() 非实时准确)
基本用法:创建与常用操作
直接 new 即可实例化,泛型类型需明确:
ConcurrentLinkedQueue
关键方法说明:
- offer(E e):线程安全入队,成功返回 true;e 为 null 时抛异常
- poll():线程安全出队,队列空时返回 null(非阻塞)
- peek():仅查看队首元素,不移除;空队列返回 null
- isEmpty():线程安全判断是否为空(比 size()==0 更可靠)
注意:size() 方法不是原子操作,高并发下可能不准,官方文档明确建议避免用于条件判断(例如 while(queue.size() > 0) 是危险的)。
多线程协作示例(生产者-消费者)
以下是一个典型无锁协作模式,多个线程并发写入,另一组线程并发读取:
// 生产者线程
Runnable producer = () -> {
for (int i = 0; i
queue.offer("task-" + i); // 无锁插入
}
};
// 消费者线程
Runnable consumer = () -> {
int count = 0;
while (count
String task = queue.poll(); // 可能返回 null
if (task != null) {
System.out.println(Thread.currentThread().getName() + " processed: " + task);
count++;
}
}
};
实际使用中,消费者常配合循环+短暂休眠或 yield 避免忙等;若需精确消费总数,应由外部计数器或使用 CountDownLatch 协调。
注意事项与常见误区
ConcurrentLinkedQueue 虽高效,但有几点易被忽略:
- 不保证强一致性:size()、toArray() 等遍历类方法在并发修改时可能反映中间状态,不可用于同步逻辑判断
- 内存可见性已内置:所有操作天然满足 happens-before,无需额外 volatile 或 synchronized
- 不能替代 BlockingQueue:没有 take()、put() 等阻塞方法,需要阻塞语义请选 LinkedBlockingQueue 或 SynchronousQueue
- 扩容无成本:作为无界队列,内部节点动态创建,但极端情况下可能引发 OOM,必要时应结合背压策略(如限流、丢弃)
不复杂但容易忽略细节,用对场景才能发挥它的无锁优势。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











