您的位置:

Java CAS原理详解

一、CAS介绍

CAS(Compare and Swap),即比较-交换操作,是一种原子操作。原子操作是指不可中断的一个或一系列操作。这个操作被看做是一个整体,不可能被线程调度机制打断,保证了并发安全性。其中CAS是一种基于硬件实现的操作,可以实现不加锁的并发安全。

CAS一般包括三个操作数:内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。整个比较和交换操作是一个原子操作。

二、CAS的应用

CAS主要应用于多线程并发操作中,例如在Java中,常用的Atomic系列类,就是使用CAS实现的原子操作类,如下所示:

public class AtomicInteger {
    private volatile int value;
 
    public AtomicInteger(int value) {
        this.value = value;
    }
 
    public final int get() {
        return value;
    }
 
    public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }
 
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
}

上面代码中的getAndIncrement()方法就是使用CAS实现的原子操作,其实现方式可以简单描述为:

  1. 获取当前值(current)
  2. 计算新的值(next)
  3. 使用CAS更新值,如果更新成功,则返回当前值
  4. 如果更新失败,则重新获取当前值进行下一次操作

三、CAS的优缺点

优点

  • 无锁化并发编程,避免了锁的开销
  • 确保了并发条件下的数据一致性和正确性
  • 可以减少内存的使用,提高内存效率
  • 可扩展性比锁高,可以有效避免死锁问题

缺点

  • CAS操作的ABA问题:如果位置V一开始是A,后来被改为B,然后又被改回为A,那么CAS会认为它从来没有被修改过。解决方式可以加上版本号,每次修改都会将版本号+1。
  • CAS操作只能保证一个共享变量的原子操作,对多个共享变量的操作必须加锁
  • CAS操作失败的开销比较大,包括循环时间、CPU消耗等资源的消耗,如果CAS机制适用的情景是非常重要的

四、CAS的实现

下面给出一个CAS的简单实现,用于说明CAS的原理:

public class ThreadSafeCounter {
    private volatile int count;
 
    public int getCount() {
        return count;
    }
 
    public void increment() {
        int oldValue = count;
        while (!compareAndSet(oldValue, oldValue + 1)) {
            oldValue = count;
        }
    }
 
    public boolean compareAndSet(int oldValue, int newValue) {
        if (count == oldValue) {
            count = newValue;
            return true;
        }
        return false;
    }
}

上面代码中的increment()方法使用了CAS实现的原子操作,其实现方式可以简单描述为:

  1. 获取当前值oldValue
  2. 如果使用CAS更新值失败,则重新获取当前值oldValue
  3. 重复执行第二步,直到更新成功

五、总结

CAS作为一种基于硬件实现的操作,可以实现不加锁的并发安全,常见的应用场景是多线程并发操作。虽然CAS有其优势和缺点,但是在特定的场景下,可以有效地提高代码的效率和性能。