【并发编程基石】CAS无锁算法详解:原理、实现与应用场景
一、什么是CAS?
CAS(Compare-And-Swap) 是现代并发编程的核心算法之一,它通过处理器指令级的原子操作实现线程安全,无需传统锁机制。其核心逻辑可以用一个公式表示:
CAS(V, E, N) {if (V == E) { // 比较当前值是否等于预期值V = N // 如果相等则更新return true}return false
}
二、CAS的工作原理
- 读取共享变量V(假设值为A)
- 计算新值B
- 提交时检查:如果V仍等于A,则更新为B;否则重试或放弃
三、Java中的CAS实现
3.1 Atomic原子类示例
AtomicInteger count = new AtomicInteger(0);// 线程安全的递增
count.incrementAndGet(); // 源码实现(JDK17)
public final int incrementAndGet() {return U.getAndAddInt(this, VALUE, 1) + 1;
}
3.2 Unsafe类底层调用
// HotSpot虚拟机实现
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
{oop p = JNIHandles::resolve(obj);jint* addr = (jint*)index_oop_from_field_offset_long(p, offset);return Atomic::cmpxchg(x, addr, e) == e;
}
四、CAS的典型应用场景
4.1 并发计数器
// 传统锁方案 vs CAS方案
synchronized void increment() { // 悲观锁count++;
}void increment() { // 乐观锁int old;do {old = count.get();} while (!count.compareAndSet(old, old+1));
}
4.2 无锁队列(ConcurrentLinkedQueue)
// JDK实现片段
Node<E> newNode = new Node<E>(e);
while (true) {Node<E> t = tail;if (t.casNext(null, newNode) && casTail(t, newNode)) {return true;}
}
五、CAS的优缺点分析
优势
- 高性能:避免线程上下文切换
- 无死锁:不存在锁的循环等待
- 细粒度:变量级别的并发控制
缺陷
问题类型 | 说明 | 解决方案 |
---|---|---|
ABA问题 | 值从A→B→A变化导致误判 | 使用AtomicStampedReference |
自旋开销 | 长时间竞争浪费CPU | 限制自旋次数或升级为锁 |
单一变量 | 只能保证单个变量原子性 | 使用AtomicReference |
六、CAS在分布式系统中的变种
6.1 乐观锁实现
UPDATE products
SET stock = stock - 1, version = version + 1
WHERE id = 100 AND version = 5
6.2 Redis的WATCH/MULTI
WATCH stock_key
MULTI
DECR stock_key
EXEC
七、最佳实践建议
- 短平快操作:CAS适合简单的原子操作
- 低竞争场景:高竞争时考虑LongAdder
- 版本号机制:重要数据添加时间戳/版本号
- 失败策略:设置合理的重试次数上限