比较与交换CAS
# 比较与交换CAS
# CAS
CAS 全称 Compare And Swap,比较与交换,是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步。java.util.concurrent
包中的原子类就是通过 CAS 来实现了乐观锁。
CAS 算法涉及的三个操作数:
- 需要读写的内存值 V
- 进行比较的值 A
- 要写入的新值 B
当 V=A 时,CAS 通过原子方式用新值B来更新V的值,否则不会执行任何操作。一般情况下,“更新”是一个不断重试的操作。
乐观锁的主要实现方式就是 CAS
# Unsafe类
在Java中,Unsafe 类是 CAS 的核心类,存在于 sun.misc
包中,由于 Java 方法无法直接访问底层系统,需要本地(Native)方法来访问,Unsafe 相当于一个后门,其内部方法操作可以像 C 的指针一样直接操作内存。
Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都直接调用操作系统底层资源执行相应任务。
CAS,是一条CPU并发原语。它的功能是判断内存某个位置是否位预期值,如果是则更改为新的值,这个过程是原子的。JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。
原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成数据不一致问题。
public final class Unsafe {
...
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
...
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# CAS的问题
- ABA问题,CAS需要在操作值的时候检查内存值是否发生变化,没有发生变化才会更新内存值。但是如果内存值原来是A,后来变成B,然后又变成了A,那么CAS进行检查时会发现值没有发生变化,但实际上是有变化的。ABA问题的解决思路就是在变量前面添加版本号,每次变量更新的时候都把版本号加一,这样变化过程就从“A-B-A“编程”1A-2B-3A“。
- 循环时间长开销大,CAS操作如果长时间不成功,会导致其一直自选,给CPU带来非常大的开销。
- 只能保证一个共享变量的原子操作,对一个共享变量执行操作时,CAS能够保证原子操作,但是多个共享变量操作时,CAS是无法保证操作的原子性。
编辑 (opens new window)
上次更新: 2023/08/20, 21:21:52