CAS
在 Java 中,CAS(Compare and Swap)是一种无锁的原子操作机制,它可以在不加锁的情况下实现对共享变量的原子更新。
原理
CAS 操作包含三个操作数:内存位置(V)、预期原值(A)和新值(B)。CAS 操作会将内存位置 V 中的值与预期原值 A 进行比较,如果相等,则将内存位置 V 中的值更新为新值 B,否则不进行任何操作。整个操作是原子性的,由硬件指令保证。
实例代码
在 Java 中,可以使用java.util.concurrent.atomic包下的原子类来使用 CAS 操作。例如,AtomicInteger类提供了compareAndSet方法来实现 CAS 操作。
import java.util.concurrent.atomic.AtomicInteger;
public class CASExample {
public static void main(String[] args) {
// 创建一个AtomicInteger对象
AtomicInteger atomicInteger = new AtomicInteger(0);
// 在线程中使用CAS更新AtomicInteger的值
Thread thread1 = new Thread(() -> {
int expectedValue = atomicInteger.get();
int newValue = expectedValue + 1;
// 使用CAS更新值,如果更新成功,打印更新后的结果
if (atomicInteger.compareAndSet(expectedValue, newValue)) {
System.out.println("Thread 1: Updated value to " + newValue);
}
});
Thread thread2 = new Thread(() -> {
int expectedValue = atomicInteger.get();
int newValue = expectedValue + 2;
// 使用CAS更新值,如果更新成功,打印更新后的结果
if (atomicInteger.compareAndSet(expectedValue, newValue)) {
System.out.println("Thread 2: Updated value to " + newValue);
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 打印最终的值
System.out.println("Final value: " + atomicInteger.get());
}
}
好处
- 无锁开销:相比于传统的加锁方式,CAS 避免了线程阻塞和唤醒的开销,提高了并发性能。尤其是在高并发场景下,当竞争不激烈时,CAS 能够以较低的成本实现数据的原子更新。
- 提高并发性:多个线程可以同时尝试使用 CAS 更新共享变量,而不会像使用锁那样导致线程阻塞,从而提高了系统的并发性和吞吐量。
坏处
- ABA 问题
如果一个变量 V 初次读取时的值为 A,并且在准备赋值的时候检查到它的值仍然为 A,那不能说明它的值没有被其他线程修改过。因为在这期间它可能被改为其他值,然后又改回了 A。解决 ABA 问题可以使用AtomicStampedReference类,它通过给变量添加版本号来解决 ABA 问题。 - 自旋开销
在 CAS 操作失败时,通常会通过自旋(不断重试)来再次尝试更新。如果自旋次数过多,会浪费大量的 CPU 资源。特别是在竞争激烈的情况下,可能导致 CAS 操作长时间无法成功,影响系统性能。 - 不适用于复杂操作
CAS 只能对单个变量进行原子操作,对于多个变量的原子更新或者复杂的业务逻辑,CAS 可能无法直接满足需求,需要结合其他技术来实现。

浙公网安备 33010602011771号