CAS与原子操作类Atomic CAS(Compare And Swap)是并发编程的底层基石,Java 的原子类都基于 CAS 实现。本文从原理到应用全面解析。
CAS 原理 CAS 是一条 CPU 原子指令,包含三个操作数:
当且仅当 V 的值等于 A 时,才将 V 的值更新为 B,否则什么都不做。
while (true) { int current = get(); // 读取当前值 int newValue = current + 1; // 计算新值 if (compareAndSwap(current, newValue)) { // CAS操作 break; // 成功 } // 失败,重试 }
Java 中的 CAS 实现 Unsafe 类 public final class Unsafe { public final native boolean compareAndSwapObject (Object o, long offset, Object expected, Object x) ; public final native boolean compareAndSwapInt (Object o, long offset, int expected, int x) ; public final native boolean compareAndSwapLong (Object o, long offset, long expected, long x) ; }
注意 :Unsafe 不能直接调用,原子类内部使用。
Atomic 原子类家族 基本类型 AtomicInteger ai = new AtomicInteger (0 );int newVal = ai.incrementAndGet(); int oldVal = ai.getAndIncrement(); ai.decrementAndGet(); ai.addAndGet(5 ); ai.getAndAdd(5 ); boolean success = ai.compareAndSet(0 , 1 );
数组类型 AtomicIntegerArray array = new AtomicIntegerArray (10 );array.set(0 , 100 ); int val = array.incrementAndGet(0 );
引用类型 AtomicReference<User> ref = new AtomicReference <>(); ref.set(new User ("张三" )); User old = ref.getAndSet(new User ("李四" ));User expected = ref.get();ref.compareAndSet(expected, new User ("王五" ));
字段更新器 public class User { private volatile int age; } AtomicIntegerFieldUpdater<User> updater = AtomicIntegerFieldUpdater.newUpdater(User.class, "age" ); User user = new User ();updater.incrementAndGet(user);
累加器(JDK 8+) 高并发场景下比 AtomicLong 性能更好:
LongAdder adder = new LongAdder ();adder.increment(); adder.add(100 ); long sum = adder.sum();
原理 :内部维护 Cell 数组,线程分散到不同 Cell 上累加,最后求和。
LongAccumulator accumulator = new LongAccumulator (Long::max, 0 );accumulator.accumulate(100 ); accumulator.accumulate(200 ); long max = accumulator.get();
ABA 问题 什么是 ABA 问题 线程A读取值A 线程B将A改为B,又改回A 线程A的CAS操作成功,但实际上值已经被修改过
AtomicReference<Node> top = new AtomicReference <>(); Node node1 = top.get(); top.compareAndSet(A, B); top.compareAndSet(B, A); top.compareAndSet(A, newNode);
解决方案:AtomicStampedReference 增加版本号(stamp)控制:
AtomicStampedReference<String> ref = new AtomicStampedReference <>("A" , 0 ); int [] stampHolder = new int [1 ];String value = ref.get(stampHolder);int stamp = stampHolder[0 ];ref.compareAndSet("A" , "B" , stamp, stamp + 1 );
AtomicMarkableReference 另一种方案,使用 boolean 标记:
AtomicMarkableReference<String> ref = new AtomicMarkableReference <>("A" , false ); boolean [] markHolder = new boolean [1 ];String value = ref.get(markHolder);ref.compareAndSet("A" , "B" , false , true );
CAS 的优缺点 优点
无锁 :没有线程阻塞和唤醒开销
高性能 :竞争不激烈时效率极高
原子性 :硬件级别保证
缺点
自旋开销 :竞争激烈时 CPU 空转
ABA 问题 :需要额外处理
只能保证单个变量原子性 :无法解决多变量一致性问题
性能对比 private long count1;public synchronized void increment1 () { count1++; }private AtomicLong count2 = new AtomicLong (0 );public void increment2 () { count2.incrementAndGet(); }private LongAdder count3 = new LongAdder ();public void increment3 () { count3.increment(); }
实现
低竞争
高竞争
synchronized
中
差
AtomicLong
好
差(大量自旋)
LongAdder
好
很好(分散竞争)
实际应用场景 1. 计数器 public class ConcurrentCounter { private final LongAdder count = new LongAdder (); public void increment () { count.increment(); } public long get () { return count.sum(); } }
2. 序列号生成 public class IdGenerator { private final AtomicLong sequence = new AtomicLong (0 ); public long nextId () { return sequence.incrementAndGet(); } }
3. 乐观锁实现 public class OptimisticLock { private final AtomicStampedReference<Data> ref; public void update (Data newData) { int [] stamp = new int [1 ]; Data current = ref.get(stamp); Data processed = process(current, newData); if (!ref.compareAndSet(current, processed, stamp[0 ], stamp[0 ] + 1 )) { throw new ConcurrentModificationException (); } } }
总结 CAS 是无锁并发的基础,Java 通过 sun.misc.Unsafe 提供 CAS 能力,上层封装了丰富的原子类:
AtomicXxx :基本类型原子操作
AtomicXxxArray :数组原子操作
AtomicReference :引用原子操作
AtomicStampedReference :解决 ABA 问题
LongAdder/LongAccumulator :高并发累加器
在竞争激烈的高并发场景下,优先使用 LongAdder 替代 AtomicLong。