zoukankan      html  css  js  c++  java
  • 浅尝CAS

    什么是CAS

          CAS全称为 Compare-And-Swap,理解就是对比交换,是一条cpu的原子指令,cpu先比较两个值是否相等,然后原子的更新某个位置的值

          java中为我们提供了AtomicInteger 原子类(底层基于CAS进行更新数据的),不需要加锁就在多线程并发场景下实现数据的一致性

          我们来看 1.8之前java源码AtomicInteger有一个incrementAndGet的自增方法;

        public final int incrementAndGet() {
            for (; ; ) {
                int current = get();
                int next = current + 1;
                if (compareAndSet(current, next))
                    return next;
            }
        }

           在一个循环里,每次去获取当前的值current,然后将当前值current+1赋值给next,然后将current和next放到compareAndSet中进行比较,如果返回true那么就

     return next的值,如果失败,那么继续进行上述操作,自旋锁操作

    在看下边

    public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueoffset, expect, update);
    }

           可以看到这个compareAndSet方法有两个参数,分别叫expect和update,从字面上理解就是预期的值和更新的值,里边调用了一个compareAndSwapInt的方法,有四个参数分别是当前的值this、valueOffset、预期值expect、更新的值update,其中expect和update是通过参数传过来的,就是incrementAndGet方法中的current和next,this当前值和预期值expect也就是current进行比较,如果相等,就把值更新为update也就是next,这样此次自增操作完成,如果不等,说明有别的线程在进行操作,他就一直自旋等待
    下边来看下java1.8的源码,在jdk1.8中,直接使用了Unsafe的getAndAddInt方法

    /**
         * Atomically adds the given value to the current value.
         *
         * @param delta the value to add
         * @return the previous value
         */
        public final int getAndAdd(int delta) {
            return unsafe.getAndAddInt(this, valueOffset, delta);
        }
    
        /**
         * Atomically increments by one the current value.
         *
         * @return the updated value
         */
        public final int incrementAndGet() {
            return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
        }

    反编译了Unsafe,得到了如下代码:

    public final int getAndAddInt(Object obj, long l, int i)
    {
        int j;
        do
            j = getIntVolatile(obj, l);
        while(!compareAndSwapInt(obj, l, j, j + i));
        return j;
    }
    public native int getIntVolatile(Object obj, long l);
    public final native boolean compareAndSwapInt(Object obj, long l, int i, int j);

    从源码中发现,内部使用自旋的方式进行CAS更新(while循环进行CAS更新,如果更新失败,则循环再次重试)

    CAS缺点

         1.ABA问题。因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A

       2.循环时间长开销大,自旋CAS如果长时间不成功,会给CPU带来非常大的消耗


    以上是对CAS的理解,欢迎大佬批评指正
  • 相关阅读:
    php操作mysql数据库
    Java获得某目录下文件总大小
    Flex Air 主窗口和多个子窗口从属显示 拂晓风起
    actionscript AES 加密 解密 拂晓风起
    Flex 可以拖出窗口的panel 拖动panel变为窗口 拂晓风起
    Flash builder打包as actionscript代码,发布swc 拂晓风起
    网站安全登录 web应用安全登录 密码 防截获 拂晓风起
    Flex透明窗体做法 spark的Window加Skin 拂晓风起
    PHP开发环境搭建 (XAMPP+Xdebug+netbeans,配置调试) 拂晓风起
    SSH 项目过程中遇到的问题和解决方法汇总 struts2 spring hibernate 拂晓风起
  • 原文地址:https://www.cnblogs.com/innocenter/p/12894445.html
Copyright © 2011-2022 走看看