用while循环配合AtomicReference实现无锁链表插入,核心是不断CAS更新头节点或前驱节点next字段直至成功;头插法原子更新head引用,尾插法则需循环定位tail并CAS其next。

用 while 循环配合 AtomicReference 实现无锁链表插入,核心是不断尝试 CAS(Compare-And-Swap)更新头节点或前驱节点的 next 字段,直到成功为止。它不依赖 synchronized 或锁,靠硬件 CAS 指令保证原子性,适合高并发场景。
理解关键组件:AtomicReference 与 CAS 语义
AtomicReference 封装了一个可被原子更新的对象引用。它的 compareAndSet(expected, updated) 方法是无锁操作的基础:仅当当前值等于 expected 时,才将值设为 updated,并返回是否成功。
这正好对应“检查-修改-写回”(Check-Then-Act)的原子化需求——比如“若当前节点的 next 是 A,就把它设成新节点”,失败则重试。
定义线程安全的链表节点
每个节点需用 AtomicReference 管理后继指针:
static class Node {
final int value;
final AtomicReference<Node> next;
Node(int value) {
this.value = value;
this.next = new AtomicReference<>();
}
}
注意:value 设为 final,避免可见性问题;next 必须是 AtomicReference,否则无法 CAS 更新。
头插法:用 while + CAS 更新 head 引用
最简单的无锁插入是头插(插入到链表最前面),只需原子更新头节点引用:
private final AtomicReference<Node> head = new AtomicReference<>();
public void insertHead(int value) {
Node newNode = new Node(value);
Node currentHead;
do {
currentHead = head.get();
newNode.next.set(currentHead); // 新节点指向当前头
} while (!head.compareAndSet(currentHead, newNode)); // 尝试替换头节点
}
- 先读取当前
head,让新节点指向它; - 再用
compareAndSet尝试把head改成新节点; - 若期间有其他线程抢先更新了
head,CAS 失败,循环重试。
尾插或中间插入:需定位前驱节点并 CAS 其 next
尾插更复杂,因为要找到最后一个节点(next == null),然后 CAS 它的 next。必须用“循环定位 + 循环 CAS”双重保障:
public void insertTail(int value) {
Node newNode = new Node(value);
Node current;
Node next;
do {
current = head.get();
if (current == null) { // 空链表,尝试设 head
if (head.compareAndSet(null, newNode)) {
return;
} else {
continue; // head 已被设,重新开始
}
}
// 向后遍历到 tail
while ((next = current.next.get()) != null) {
current = next;
}
// current 是 tail,尝试将它的 next 设为 newNode
} while (!current.next.compareAndSet(null, newNode));
}
- 外层
do-while保证整体插入逻辑重试; - 内层
while遍历时,每一步都用get()读取最新next,避免基于过期快照操作; - 最后对
current.next执行compareAndSet(null, newNode),只在它仍是null时才成功。
不复杂但容易忽略:所有读取(get())和写入(compareAndSet)都必须作用于 AtomicReference 字段,且每次 CAS 前都要重新获取最新值,不能缓存旧引用做多次判断。

















