Java 中的 CAS 机制详解
CAS(比较并交换)是一种基于硬件原子操作的无锁多线程同步机制。Java 通过 Unsafe 类和 java.util.concurrent.atomic 包实现 CAS,提供 AtomicInteger 等原子类。CAS 包含 V、A、B 三个参数,支持 x86/ARM 等架构指令。优点包括高性能、非阻塞;缺点包括 ABA 问题、自旋开销及单变量限制。适用于计数器、状态标志及无锁数据结构,高竞争场景需谨慎使用。

CAS(比较并交换)是一种基于硬件原子操作的无锁多线程同步机制。Java 通过 Unsafe 类和 java.util.concurrent.atomic 包实现 CAS,提供 AtomicInteger 等原子类。CAS 包含 V、A、B 三个参数,支持 x86/ARM 等架构指令。优点包括高性能、非阻塞;缺点包括 ABA 问题、自旋开销及单变量限制。适用于计数器、状态标志及无锁数据结构,高竞争场景需谨慎使用。

CAS(Compare And Swap,比较并交换) 是一种无锁(Lock-Free)的多线程同步机制,它基于硬件提供的原子性操作来实现线程安全。CAS 是现代并发编程中的核心技术,广泛应用于 Java 并发包中。
CAS 操作包含三个参数:
boolean cas(Object v, Object a, Object b) {
if (v == a) {
// 比较:当前值是否等于预期值
v = b;
// 交换:设置新值
return true;
// 成功
} else {
return false;
// 失败
}
}
CAS 操作在硬件层面是原子的,主要通过以下方式实现:
CMPXCHG(Compare and Exchange)指令LDREX/STREX(Load-Exclusive/Store-Exclusive)指令LL/SC(Load-Linked/Store-Conditional)指令Java 通过 Unsafe 类提供底层 CAS 操作:
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class CASExample {
private static Unsafe unsafe;
private volatile int value;
private static long valueOffset;
static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
valueOffset = unsafe.objectFieldOffset(CASExample.class.getDeclaredField("value"));
} catch (Exception e) {
throw new Error(e);
}
}
// 自定义 CAS 操作
public boolean compareAndSet(int expectedValue, int newValue) {
return unsafe.compareAndSwapInt(this, valueOffset, expectedValue, newValue);
}
}
Java 提供了丰富的原子类,内部均基于 CAS 实现:
| 类名 | 描述 | 常用方法 |
|---|---|---|
AtomicInteger | 原子整型 | get(), set(), compareAndSet(), incrementAndGet() |
AtomicLong | 原子长整型 | get(), addAndGet(), compareAndSet() |
AtomicBoolean | 原子布尔型 | get(), compareAndSet() |
AtomicReference<V> | 原子引用 | get(), set(), compareAndSet() |
AtomicIntegerArray | 原子整型数组 | getAndSet(), compareAndSet() |
AtomicStampedReference<V> | 带版本号的原子引用 | 解决 ABA 问题 |
import java.util.concurrent.atomic.AtomicInteger;
public class BasicCASExample {
private AtomicInteger counter = new AtomicInteger(0);
public void increment() {
int oldValue, newValue;
do {
oldValue = counter.get(); // 读取当前值
newValue = oldValue + 1; // 计算新值
} while (!counter.compareAndSet(oldValue, newValue)); // CAS 循环直到成功
}
public int getValue() {
return counter.get();
}
public static void main(String[] args) throws InterruptedException {
BasicCASExample example = new BasicCASExample();
// 创建 10 个线程并发递增
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
example.increment();
}
});
threads[i].start();
}
for (Thread t : threads) {
t.join();
}
System.out.println("最终结果:" + example.getValue()); // 输出:10000
}
}
import java.util.concurrent.atomic.AtomicReference;
public class ConcurrentStack<T> {
private static class Node<T> {
final T value;
Node<T> next;
Node(T value) {
this.value = value;
}
}
private AtomicReference<Node<T>> top = new AtomicReference<>();
// 无锁 push 操作
public void push(T value) {
Node<T> newNode = new Node<>(value);
Node<T> oldHead;
do {
oldHead = top.get(); // 读取当前栈顶
newNode.next = oldHead; // 新节点指向旧栈顶
} while (!top.compareAndSet(oldHead, newNode)); // CAS 更新栈顶
}
// 无锁 pop 操作
public T pop() {
Node<T> oldHead, newHead;
do {
oldHead = top.get(); // 读取当前栈顶
if (oldHead == null) {
return null; // 栈为空
}
newHead = oldHead.next; // 新栈顶为下一个节点
} while (!top.compareAndSet(oldHead, newHead)); // CAS 更新栈顶
return oldHead.value;
}
public boolean isEmpty() {
return top.get() == null;
}
}
import java.util.concurrent.atomic.AtomicBoolean;
public class SpinLock {
private AtomicBoolean locked = new AtomicBoolean(false);
public void lock() {
// 自旋等待直到获取锁
while (!locked.compareAndSet(false, true)) {
// 可添加 Thread.yield() 或等待策略减少 CPU 占用
Thread.yield();
}
}
public void unlock() {
locked.set(false);
}
public boolean tryLock() {
return locked.compareAndSet(false, true);
}
}
什么是 ABA 问题: 指内存值由 A 变为 B,又变回 A,CAS 无法感知变化。
import java.util.concurrent.atomic.AtomicStampedReference;
public class ABASolutionExample {
public static void main(String[] args) {
// 创建初始值,使用静态变量避免自动装箱创建新对象
final Integer value100 = 100;
final Integer value200 = 200;
final Integer value300 = 300;
// 初始值 100,版本号 0
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(value100, 0);
int[] stampHolder = new int[1];
int oldValue = ref.get(stampHolder);
int oldStamp = stampHolder[0];
System.out.println("初始:值=" + oldValue + ", 版本=" + oldStamp);
// 模拟 ABA
// ====================================================================
// 注意:不能写成这样,否则 Integer 对象会被缓存,导致版本号不变
// 步骤 1:100 → 200 ref.compareAndSet(100, 200, 0, 1); 这里的 100 和 200 都是自动装箱的 Integer 对象
// 步骤 2:200 → 100 ref.compareAndSet(200, 100, 1, 2); 这里的 200 是新创建的 Integer 对象,与步骤 1 中的 200 不是同一个对象
// ====================================================================
// A -> B
int[] stampHolder1 = new int[1];
Integer currentValue1 = ref.get(stampHolder1);
ref.compareAndSet(currentValue1, value200, stampHolder1[0], stampHolder1[0] + 1);
// B -> A
int[] stampHolder2 = new int[1];
Integer currentValue2 = ref.get(stampHolder2);
ref.compareAndSet(currentValue2, value100, stampHolder2[0], stampHolder2[0] + 1);
// 尝试 CAS(会失败,因为版本变了)
boolean success = ref.compareAndSet(oldValue, value300, oldStamp, oldStamp + 1);
System.out.println("结果:" + (success ? "成功" : "失败"));
System.out.println("原因:版本从" + oldStamp + "变为" + ref.getStamp());
}
}
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
public class CASvsLockBenchmark {
private static final int THREAD_COUNT = 10;
private static final int ITERATIONS = 1000000;
// 测试方法
private static long benchmark(Runnable task) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(THREAD_COUNT);
Thread[] threads = new Thread[THREAD_COUNT];
long start = System.currentTimeMillis();
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new Thread(() -> {
task.run();
latch.countDown();
});
threads[i].start();
}
latch.await();
long end = System.currentTimeMillis();
return end - start;
}
public static void main(String[] args) throws InterruptedException {
// 1. 测试 synchronized
Object lock = new Object();
int[] syncCounter = {0};
long syncTime = benchmark(() -> {
for (int j = 0; j < ITERATIONS; j++) {
synchronized (lock) {
syncCounter[0]++;
}
}
});
// 2. 测试 ReentrantLock
ReentrantLock reentrantLock = new ReentrantLock();
int[] lockCounter = {0};
long lockTime = benchmark(() -> {
for (int j = 0; j < ITERATIONS; j++) {
reentrantLock.lock();
try {
lockCounter[0]++;
} finally {
reentrantLock.unlock();
}
}
});
// 3. 测试 CAS (AtomicInteger)
AtomicInteger atomicCounter = new AtomicInteger(0);
long atomicTime = benchmark(() -> {
for (int j = 0; j < ITERATIONS; j++) {
atomicCounter.incrementAndGet();
}
});
System.out.println("测试结果(越低越好):");
System.out.println("synchronized: " + syncTime + "ms");
System.out.println("ReentrantLock: " + lockTime + "ms");
System.out.println("CAS (AtomicInteger): " + atomicTime + "ms");
// 验证结果
System.out.println("\n最终计数验证:");
System.out.println("synchronized: " + syncCounter[0]);
System.out.println("ReentrantLock: " + lockCounter[0]);
System.out.println("CAS: " + atomicCounter.get());
}
}
典型测试结果(10 个线程,每个递增 100 万次):
AtomicInteger、AtomicLongAtomicBoolean// ✅ 优先使用 JDK 提供的原子类
AtomicInteger counter = new AtomicInteger(0);
AtomicReference<User> userRef = new AtomicReference<>();
// ❌ 纯自旋,CPU 消耗大
while (!atomicRef.compareAndSet(oldValue, newValue)) {
// 空循环
}
// ✅ 添加退避策略
int retries = 0;
while (!atomicRef.compareAndSet(oldValue, newValue)) {
if (retries++ > 100) {
Thread.yield();
}
// 或者使用指数退避
}
// 使用带版本号的原子引用
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(0, 0);
// 或者使用 AtomicMarkableReference
AtomicMarkableReference<Integer> markedRef = new AtomicMarkableReference<>(0, false);
public void addIfLessThan(int max) {
int current;
int newValue;
do {
current = atomicInt.get();
if (current >= max) {
return; // 条件不满足
}
newValue = current + 1;
} while (!atomicInt.compareAndSet(current, newValue));
}
CAS 是现代并发编程的基石,它通过硬件支持的原子操作实现了高效的无锁同步。在实际开发中:
java.util.concurrent.atomic 包提供的原子类通过合理使用 CAS,可以在保持线程安全的同时获得比传统锁机制更好的性能,特别是在多核处理器和高并发场景下。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online