CAS知识点

68 阅读1分钟

什么是CAS

(compare and swap)比较并交换,是cpu的一个原子指令,不存在线程安全问题

CAS的操作步骤

  1. 记录内存中要修改的旧值,
  2. 产生要使用的新值,
  3. 对比内存中的值是否跟记录的旧值一致,
  4. 如果一致使用新值覆盖,如果不一致做自旋操作

源代码

//创建一个原子类,并递增加一
AtomicInteger atomicInteger = new AtomicInteger();
atomicInteger.incrementAndGet();
/**
 * Atomically increments by one the current value.
 *
 * @return the updated value
 */
public final int incrementAndGet() {
    //通过unsafe类实现原子操作加一
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            //获取内存中的值
            var5 = this.getIntVolatile(var1, var2);
            //通过c来实现比较并赋值(实现内存中加一)
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
        //返回内存中的老值
        return var5;
    }

ABA问题

ABA问题是指CAS在与记录的旧值比较的内存中的值发生的改变,最终又改成了原来的值。对比依然能通过,但是值已经发生了改变;例如:记录的旧值为1,记录后内存中的1改成了2,后来又改成了1,在最后的对比时虽然值发生了变化,但是依然能通过 解决办法,记录旧值的同时增加一个版本号,在对比旧值的同时对比版本号

import java.util.concurrent.atomic.AtomicStampedReference;

public class ABASolution {
    public static void main(String[] args) {
        // 初始值为100,版本号为0
        AtomicStampedReference<Integer> atomicStampedRef = new AtomicStampedReference<>(100, 0);

            int stamp = atomicStampedRef.getStamp();
            int value = atomicStampedRef.getReference();
            // 模拟一个ABA问题
            
            boolean success = atomicStampedRef.compareAndSet(value, value + 10, stamp, stamp + 1);
            if (!success) {
                System.out.println("ABA problem detected!");
            }
        
    }
}