CAS


文章来源于:

https://www.bilibili.com/video/BV18b411M7xz?p=12

CAS是什么?

  • Compare Ana Swap
  • 一条CPU的原子指令,不会造成数据不一致问题
  • 是乐观锁的一种实现
    public static void main(String[] args) {

        AtomicInteger atomicInteger = new AtomicInteger(5);
        // System.out.println(atomicInteger.compareAndSet(5,7));//true
        //ABA问题
        System.out.println(atomicInteger.compareAndSet(7,5));//true
        System.out.println(atomicInteger.compareAndSet(5,8));//true
    }

CAS原理

CAS 是实现自旋锁的基础,CAS 利用 CPU 指令保证了操作的原子性,以达到锁的效果,至于自旋呢,看字面意思也很明白,自己旋转,翻译成人话就是循环,一般是用一个无限循环实现。这样一来,一个无限循环中,执行一个 CAS 操作,当操作成功,返回 true 时,循环结束;当返回 false 时,接着执行循环,继续尝试 CAS 操作,直到返回 true。

AtomicInteger

  1. Unsafe是CAs的核心类,存在于sun.misc包中。像C指针一样直接操作内存,直接调用操作系统底层执行对应任务。
  2. valueOffset,表示变量在内存中的偏移地址。
  3. 变量value用volatile修饰,保持多线程之间的可见性。

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
        try {
            //
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    // volatile 修饰
    private volatile int value;

方法调用

AtomicInteger atomicInteger = new AtomicInteger(5);

int andIncrement = atomicInteger.getAndIncrement();

public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        //找出内存中的值
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
        //如果相同 +1 
        //如果不同,继续取值比较,直到更新完成
    return var5;
}

缺点

循环开销大

只能对一个变量就行操作

ABA问题

ABA问题

  • 初始值为100,线程t1将100改成101,然后又将101改回100
  • 线程t2先睡眠1秒,等待t1操作完成,然后t2线程将值改成2019
  • 可以看到,线程2修改成功

业务中的库存问题

Ribbon中负载均衡的轮询算法也是运用了CAS

解决ABA

原子引用

由单一变量变为了引用类型


AtomicReference<User> atomicReference = new AtomicReference();


## 原子时间戳引用

带版本戳的原子引用类型,版本戳为int类型。

    AtomicStampedReference atomicStampedReference = new AtomicStampedReference(2,1);

    atomicStampedReference.compareAndSet(2,3,1,1+1);

    System.out.println(atomicStampedReference.getReference());
    System.out.println(atomicStampedReference.getStamp());

AtomicMarkableReference

带版本戳的原子引用类型,版本戳为boolean类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值