CAS(比较并交换)详解

一、什么是CAS?

CAS(Compare And Swap),就是比较并交换,是解决多线程情况下,解决使用锁造成性能损耗问题的一种机制。

CAS包含三个操作数:

  • 变量内存位置(V)
  • 预期的变量原值(A)
  • 变量的新值(B)

当要对变量进行修改时,先会将内存位置的值与预期的变量原值进行比较,如果一致则将内存位置更新为新值,否则不做操作,无论哪种情况都会返回内存位置当前的值。

二、CAS的实践案例

整个JUC都是建立在CAS之上的,我们以Java8为例,看看AtomicInteger的CAS实现:

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

    /**
     * Unsafe类是提供了native方法,用于完成硬件级别的原子性操作
     * 在这里提供Unsafe.compareAndSwapInt方法来完成CAS的比较并更新
     */
    private static final Unsafe unsafe = Unsafe.getUnsafe();

    /**
     * value在内存中的偏移量,是即CAS中的内存地址V
     */
    private static final long valueOffset;

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

    private volatile int value;
    
    // 省略一大串代码

    /**
     * 通过unsafe类提供的native方法完成CAS操作
     *
     * @param expect 预期的变量原值(A)
     * @param update 变量的新值(B)
     * @return {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    /**
     * 进行CAS操作,自旋直到数据更新成功
     *
     * @param updateFunction a side-effect-free function
     * @return 更新后的值
     * @since 1.8
     */
    public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }
}

compareAndSet的CAS实现:通过Unsafe的方法,调用native方法完成了硬件级别的原子性操作。

注意,Unsafe方法可能会在未来的jdk版本中移除,而且使用一旦出现问题可能就是JVM实例崩溃级别的问题,所以官方不推荐在应用代码中使用。

三、CAS存在的问题

ABA问题:CAS在检查值的时候,只会比较预期值A与内存位置的值是否相同,如果内存位置值,经过若干次修改又变回了A ( A -> B -> A),CAS检查依旧会通过,但是实际上这个值已经修改过了。

解决方案:解决的思路就是引入类似乐观锁的版本号控制,不止比较预期值和内存位置的值,还要比较版本号是否正确。

实现案例:从JDK5开始,atomic包就提供了AtomicStampedReference类来解决ABA问题,相较CAS引入了一个标志,在比较完预期值与内存地址值之后,再对预期标志和现有标志做比较,都通过才执行更新操作。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值