CAS自旋锁

CAS:CompareAndSwap / CompareAndSet 比较和交换
首先聊一聊CAS是个什么概念:CAS字面上理解就是比较和交换。CAS包含三个元素。
  1. 期望的旧数据:以上图为例,读取m的值 m=4 ,“4”就是期望的旧数据。

  1. 最新的数据:执行m++ 后,m=5 ,"5"就是最新的数据。

  1. 内存地址:访问的内存地址,即m存放的地址,后续需要跟改m交换。

为什么叫做期望的旧数据呢?下面说一下CAS的过程。

首先,我们只看上图的左半部分。此时内存中的m=4 ,程序读取m后做m++操作,此时m变成了5。在将m=5更新到内存之前,执行CAS操作,首先判断内存中的数据还是不是为4,程序期望内存中的数据依然为4,即:期望的旧数据(意思就说在我m ++ 操作的过程中,内存中的数据没有被修改过)。CAS比较和交换,此时比较期望的旧数据与内存的数据是否相等,相等,交换内存中的数据,将内存中的数据设置为5,如果此时不相等,说明在我执行m++的过程中,内存中的数据被修改过,重新拉取内存中的数据,重复执行CAS自旋。这就是CAS的自旋操作。

CAS会产生一个ABA问题

我们看上图的右半部分,在我左边的程序执行m++的过程中,我右边的程序同样在操作内存中的m,首先将m改成3,然后将m改成5,最后再将m改成4,右边操作做完了之后,左边的程序此时CAS比较期望的旧数据与内存中的数据,m都是等于4。更新左边程序的结果m=5到内存中。

这就是ABA问题, m=4 看作A ,中间将m修改成其他的值这个就是B,最后再将m改为4 又变成了A。看上去m似乎还是4,但是其实他中间已经被修改过了。如果是基本类型修改前的m=4与修改后的m=4并没有影响。但是如果是引用数据类型,可能其他的变量被修改过了,就会产生问题,此时可以加一个version版本号区分ABA问题中的两个A,比如 第一个A版本为V.01 第二个A版本为V.02,CAS比较两个A相等,此时继续比较版本号,判断版本号不相等,说明内存中的数据被改动过,重新执行CAS自旋。

下面聊聊CAS实际场景

在JUC包下存在这样一种类型的类:AtomicXXX

AtomicInteger,AtomicLong,AtomicDouble 等。

它们内部都维护了CAS自旋锁。下面我们以AtomicInteger为例:

 /**
 * Atomically increments by one the current value.
 *
 * @return the previous value
 */
public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

/**
 * Atomically decrements by one the current value.
 *
 * @return the previous value
 */
public final int getAndDecrement() {
    return unsafe.getAndAddInt(this, valueOffset, -1);
}

可以看到AtomicInteger中有上面两个方法getAndIncrement\getAndDecrement两个原子性的方法,分别是增加1和减少1。

下面我们以getAndIncrement为例,unsafe类调用getAndAddInt方法

public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    do {
        v = getIntVolatile(o, offset);
    } while (!compareAndSwapInt(o, offset, v, v + delta));
    return v;
}

可以看到whilt条件中有一个compareAndSwapInt方法,这个就是CAS的自旋操作。

/**
 * Atomically update Java variable to <tt>x</tt> if it is currently
 * holding <tt>expected</tt>.
 * @return <tt>true</tt> if successful
 */
public final native boolean compareAndSwapInt(Object o, long offset,
                                              int expected,
                                              int x);

我们在跟进去,发现CAS是native修饰的方法,CAS自旋是CPU源于支持的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值