简单理解CAS 是什么?从原理到技术场景

232 阅读2分钟

什么是CAS

CAS=Compare And Swap,意思是等值比较交换,比较内存中的值和预期值,如果相等就更新为新值。整个过程是原子的,不会被其他线程打断。在 程序中体现是无锁化的,步骤就是:读取内存值、比较、交换;整个一体为原子性。

CAS原理:

CAS只是在应用上体现无锁,在多核CPU操作下,会通过硬件锁控制,在锁的底层其实系统是对这些操作是有加锁的,如下:

  • x86 架构:使用 LOCK CMPXCHG指令,通过总线锁或缓存锁机制确保操作期间内存访问的独占性。
  • ARM 架构:通过 LDREX(加载并标记独占访问)和 STREX(尝试存储并解锁)指令组合实现原子性。

操作流程

CAS 操作包含三个不可分割的步骤:

  • 读取内存值:从内存地址 V中读取当前值。
  • 比较预期值:将读取的值与预期值 A进行比较。
  • 条件更新:若相等,则将内存值更新为新值 B;否则放弃操作

这三个步骤在硬件层面作为一个整体执行,不会被线程切换或中断打断。

CAS注意点

  1. 一般CAS如果遇到并发是需要自旋重试的,CAS并不适合在多线程场景竞争资源非常激烈的情况操作,否则会一直自旋操作。
  2. CAS可能会出现ABA的问题,一般都是通过版本号来控制。

有什么场景使用到原子操作?

原子类在 sun.misc.Unsafe里边有很多原子操作,CAS就是在这里边如compareAndSwapInt。

  1. 并发容
  • ConcurrentHashMap 1.8的一个空桶初始化,使用CAS操作初始化桶。
  • ConcurrentLinkedQueue 无锁的入队出队操作。
  1. 原子类: AtomicIntegerAtomicLong
  • 一般用来多线程的一些计数统计,如整个web应用的访问量,多线程的操作次数等。
  1. AQS 框架
  • AbstractQueuedSynchronizer(AQS)通过 CAS 操作,同步state状态字段,从而支撑ReentrantLock等。

开发场景

  1. 统计接口访问量、用户点击量等高频操作;Web 服务统计、API 调用量监控
  2. 线程启动/停止控制

通过 AtomicBoolean实现无锁状态切换:线程池任务调度

AtomicBoolean isRunning = new AtomicBoolean(false);
public void startTask() {
    if (isRunning.compareAndSet(false, true)) {
        // 启动任务
    }
}
  1. 对象字段原子更新

对特定字段(如用户积分字段更新)进行原子操作:

class User {
    private AtomicInteger score = new AtomicInteger(0);
    public void addScore(int points) {
        score.addAndGet(points);
    }
}