• JAVA多线程之CAS


    一、什么是CAS

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

    CAS的执行原理:CAS 操作包含三个操作数,内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置的值即可。”

    二、JDK中的CAS

    java.util.concurrent.atomic 包下的类都是基于CAS实现的

    由源码我们可以看出JDK的CAS使用的unsafe中的方法,他的实现是本地方法,也就是说JDK的CAS采用的是CPU提供的CAS原语操作,并不是JDK自己实现的。

    三、CAS的缺点

    1、cpu开销大:在高并发下,许多线程,更新一变量,多次更新不成功,循环反复,给cpu带来大量压力。

    限制循环次数可以避免开销,JAVA中的自旋锁。java中的自旋锁是一种假设在不久将来,当前的线程可以获得锁,因此虚拟机会让当前想要获取锁的线程做几个空循环(这也是称为自旋的原因),在经过若干次循环后,如果得到锁,就顺利进入临界区。如果还不能获得锁,那就会将线程在操作系统层面挂起,这种方式确实也是可以提升效率的。但问题是当线程越来越多竞争很激烈时,占用CPU的时间变长会导致性能急剧下降,因此Java虚拟机内部一般对于自旋锁有一定的次数限制,可能是50或者100次循环后就放弃,直接挂起线程,让出CPU资源。

    2、ABA问题:比如说一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且two进行了一些操作变成了B,然后two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功。虽然程序正常执行了但是内存位置V中的A已经不是原来的那个A了。由于ABA问题带来的隐患,各种乐观锁的实现中通常都会用版本戳version来对记录或对象标记,避免并发操作带来的问题,在Java中,AtomicStampedReference<E>也实现了这个作用,它通过包装[E,Integer]的元组来对对象标记版本戳stamp,从而避免ABA问题

     AtomicStampedReference的构造函数中需要一个初始值和一个版本号

    compareAndSet()方法:置换前必须比较期望值与当前值以及期望值的版本号与当前值得版本号

    • V expectedReference:期望值
    • V newReference:新值
    • int expectedStamp:期望版本号
    • int newStamp:新值得版本号
    古之学者为己,今之学者为人
  • 相关阅读:
    day04 列表和元组
    Python2和Python3的区别
    Ruby学习笔记2 : 一个简单的Ruby网站,搭建ruby环境
    Patrick Hughes
    Ruby学习笔记1 -- 基本语法和数据类型, Class
    Javascript学习笔记5
    php学习笔记1——使用phpStudy进行php运行环境搭建与测试。
    Linux配置和管理msyql命令
    干净win7要做几步才能运行第一个Spring MVC 写的动态web程序
    The difference between Spring Tool Suite and Spring IDE
  • 原文地址:https://www.cnblogs.com/jalja365/p/14714573.html
Copyright © 2020-2023  润新知