首页 > 其他 > 详细

CAS

时间:2019-09-10 20:32:27      阅读:75      评论:0      收藏:0      [点我收藏+]

乐观锁与悲观锁

synchronized是悲观锁:

    每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。

CAS操作的就是乐观锁(乐观锁在Java中的使用,是无锁编程,常常采用的是CAS算法,典型的例子就是原子类):

    每次不加锁而是假设没有冲突而去完成某项操作,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。
    如果因为冲突失败就重试,直到成功为止。


悲观锁适合写操作非常多的场景,乐观锁适合读操作非常多的场景

CAS机制(Compare And Swap)

CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程。
并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题

Java中CAS操作的执行依赖于Unsafe类的方法,Unsafe类中的方法都直接调用操作系统底层资源执行相应任务


CAS机制当中使用了3个基本操作数:

    内存地址V(主内存中存放的V值,所有线程共享)

    旧的预期值A(线程上次从内存中读取的V值A存放在线程的帧栈中,每个线程私有)

    要修改的新值B(需要写入内存中并改写V值的B值)


更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,
才会将内存地址V对应的值修改为B(防止多线程并发问题)。

CAS的缺点:

1.CPU开销较大

  在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很大的压力。

2.不能保证代码块的原子性

  CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。
  比如需要保证3个变量共同进行原子性的更新,就不得不使用Synchronized了。

3.ABA问题

  CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,
  但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。

  ABA问题的解决思路就是使用版本号:

    在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。

并发包中的原子操作类(Atomic系列)

java.util.concurrent.atomic:该包中提供了许多基于CAS实现的原子操作类

AtomicInteger类中所有自增或自减的方法都间接调用Unsafe类中的getAndAddInt()方法实现了CAS操作,从而保证了线程安全


    //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;
    }

    getAndAddInt()通过一个while循环不断的重试更新要设置的值,直到成功为止

CAS

原文:https://www.cnblogs.com/loveer/p/11502521.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!