• CAS


    CAS

    CAS(Compare And Swap),是Java中的一种无锁优化,又被称作自旋锁或者乐观锁,而synchronized和ReentrantLock则是悲观锁的典型代表

    乐观锁:总是假设最好的情况,每次拿数据都认为别人不会修改数据,所以不会加锁,但是更新的时候,会判断在此期间有没有人修改过;一般基于版本号机制实现
    悲观锁:总是假设最坏的情况,每次拿数据都认为别人会修改数据,所以要加锁,别人只能等待,直到我释放锁之后别人才能拿到锁

    原子类

    在Java中的各种原子类的递增递减等方法都是使用的CAS机制保证的数据的原子操作,从而保证数据的一致性,最终调用的都是Unsafe类中的方法,这里拿AtomicInteger的incrementAndGet方法来做示例:

    //AtomicInteger中的incrementAndGet方法
    public final int incrementAndGet() {
        //因为Unsafe类中的getAndAddInt方法返回的都是期望值,也就是当前值,但此时已经内部完成了自增操作,所以这里需要对返回值进行加一后返回
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;   
    }
    
    //Unsafe中的getAndAddInt方法
    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));//执行调用JNI方法(CAS)来完成操作,如果失败则循环执行
        return var5;    //返回期望值
    }
    

    CAS原理图


    CAS原理的伪代码如下所示

    CAS(Value,Except,NewValue)
        if Value==Except
            Value=NewValue
        otherwise try again or fail
    

    细心的朋友到这里可能会问,如果在一个线程判断完Value==Expect,但是未完成Value=NewValue时Expect被其他线程修改了怎么办?
    这里完全是不用担心的,这是受底层CPU支持的原子操作,一旦执行就不能被其他线程打断,即Value==Expect和Value=NewValue要么同时完成,要么同时失败

    ABA问题

    CAS是一种乐观锁,在运行过程中假定其他线程不会来修改数据,但在高并发的环境下,难免会遇到数据被修改的情况,如果数据被修改的和原来不一样了,那么没有关系,会被检测到重新获取一次期望值再次执行即可,但是如果数据被多次修改后最终变回原值,这对于一般的CAS就没法检测了,这就是ABA问题,当数据时基本类型时,该问题并无大碍,但如果数据时引用类型时就有可能出问题,该处假定一个场景:期望值为对象A,在其他线程中把期望值设置为B,并修改了B中的值,最后将期望值又设置为对象A,这时就可能会出现问题了
    解决方法:可以在期望值对象中增加一个版本号,每当其中的值被修改时,就将版本号加一,在CAS的判断中不止判断期望值的值,而且还要判断期望值的版本号从而规避ABA问题

    如果对你有帮助,点个赞,或者打个赏吧,嘿嘿
    整理不易,请尊重博主的劳动成果

  • 相关阅读:
    浏览器内核
    link和@import的区别
    跨域iframe如何通信
    数组、对象基本操作
    浏览器兼容性问题
    微信H5开发
    前端面试整理
    js多维数组转一维数组
    js实现继承
    javascript函数闭包(closure)
  • 原文地址:https://www.cnblogs.com/Mango-Tree/p/12834441.html
Copyright © 2020-2023  润新知