【杂记】CAS 操作

1.CAS

JVM的synchronized重量级锁涉及操作系统内核态下互斥锁的使用,因此其线程阻塞和唤醒都涉及进程在用户态到内核态的频繁切换,导致重量级锁开销大,性能低,而JVM的synchronized轻量级锁使用CAS进行自旋抢锁,CAS是CPU指令级的原子操作,并处于用户态下,所有JVM轻量级锁的开销较小。由于CAS的操作具有原子性,所以在使用CAS方法操作数据时,并不会造成数据不一致性的问题。

2.Unsafe类中的CAS方法

Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全的底层操作,如直接访问系统内存资源、自主管理内存资源等,基于C++语言实现,这些方法提升java运行效率,增强java语言底层资源操作能力方面起到了很大的作用。

3.java获取CAS操作

(1)获取Unsafe实例。由于类是一个find修饰的类不允许继承的最终类,其构造函数是private类型的,因此不能实例化,可以通过反射的方式自定义地获取Unsafe实例的辅助方法。
(2)调用Unsafe提供的CAS方法,这些方法主要封装了底层CPU的CAS原子操作。Unsafe提供的CAS方法包含4个操作数——字段所在的对象、字段内存位置、预期原值及新值。在执行Unsafe的CAS方法时,这些方法首先将内存位置的值与预期值(旧的值)比较,如果相匹配,那么CPU会自动将该内存位置的值更新为新值,并返回true;如果不匹配,CPU不做任何操作,并返回false。Unsafe的CAS操作会将第一个参数(对象的指针、地址)与第二个参数(字段偏移量)组合在一起,计算出最终的内存操作地址。
(3)调用Unsafe提供的字段偏移量方法,这些方法用于获取对象中的字段(属性)偏移量,此偏移量值需要作为参数提供给CAS操作

4.使用CAS进行无锁编程

CAS是一种无锁算法,该算法关键依赖两个值-期望值(旧值)和新值,底层CPU利用原子操作判断内存原值与期望值是否相等,如果相等就给内存地址赋新值否则不做任何操作。使用CAS进行无锁编程步骤大致如下:
(1).获得字段的期望值
(2).计算出需要替换的新值
(3).通过CAS将新值放在字段的内存地址上,如果CAS失败就将重复第(1)和第(2)步骤,一直到CAS成功,这种重复称为CAS自旋。

5.原子类

Atomic操作翻译成中文是指一个不可中断的操作,即使在多个线程一起执行Atomic类型操作的时候,一个操作一旦开始,就不会被其他线程中断,所谓Atomic类,值的具有原子操作特征的类。

6.原子类分类

(1).基本原子类通过原子的方式更新java基础类型变量的值,基本原子类主要包括一下三个:整型原子类、长整型原子类、布尔型原子类,线程是安全的。其原理为:通过CAS自旋+volatile的方案实现,既保障了变量操作的线程安全性,有避免了synchronized重量级锁的高开销,使得java程序的执行效率大为提示。
(2).数组原子类通过原子方式更数组中某个元素的值,数组原子类主要包括一下三个:整型数组原子类、长整型数组原子类、引用类型数组原子类,引用类型的原子操作,只能保证引用的原子性,如果引用的为对象时,只能保证对象的原子性,不能保证对象属性的原子性。如果需要保证对象属性的原子性,就需要用到属性更新原子类。
(3).引用原子类,主要有以下几种:引用类型原子类、带有更新标记位的原子引用类型、带有更新版本号的原子引用类型
(4).字段更新原子类,主要包括一下三个:原子更新整型字段的更新器、原子更新长整型字段的更新、原子更新引用类型的字段

7.ABA问题

一个线程A从内存位置M中取出V1,另一个线程B也取出V1,现在假设线程B进行了一些操作之后将M位置的数据V1变成V2,然后又在一些操作V2变成了V1。之后线程A进程CAS操作,但是线程A发现M位置数据仍然是V1,然后线程A操作成功。尽管线程A的CAS操作成功,但是不代表这个过程没有问题,线程A操作的数据V1可能不是之前的V1,而是被线程B替换过的V1,这就是ABA问题。

8.ABA的解决方案

使用版本号(version)方式来解决,乐观锁每次在执行数据操作是都会带上一个版本号,版本号和数据的版本号一致就可以执行修改操作并对版本号执行加1操作,否则执行失败,因为每次操作的版本号都会随之增加,所以不会出现ABA的问题,因为版本号只会增加,不会减少。

9.如何提高CAS操作的性能

使用LongAdder类,以空间换取时间的方式提示高并发场景,其核心思想是:热点分离,与ConcurrentHashMap的设计思想类似:将value值分离成一个数组,当多线程访问时,通过Hash算法,将线程映射到数组的一个元素进行操作;而获取最终的value结果时,则将数组的元素进行求和。最终将单个value值演变成一系列的数组元素,从而减少了内部竞争的粒度。

10.LongAdder核心原理

AtomicLong使用内部变量value保存着实际的long值,所有的操作都是针对该value变量进行的。也就是说,在高并发环境下,value变量其实是一个热点,也就是N个线程竞争一个热点。重试线程越多,就意味着CAS的失败概率更高,从而进入恶性CAS空自旋状态。LongAdder的基本思路是分散热点,将value值分散到一个数组中,不同线程会命中到数组的不同槽(元素)中,各个线程只对自己槽中的那个值进行CAS操作。这样热点就被分散了,冲突的概率就小很多。使用LongAdder,即使线程数再多也不必担心,各个线程会分配到多个元素上去更新,增加元素个数,就可以降低value的“热度”,AtomicLong中的恶性CAS空自旋就解决了。如果要获得完整的LongAdder存储的值,只要将各个槽中的变量值累加,返回最终累加之后的值即可。LongAdder的实现思路与ConcurrentHashMap中分段锁的基本原理非常相似,本质上都是不同的线程在不同的单元上进行操作,这样减少了线程竞争,提高了并发效率。LongAdder的设计体现了空间换时间的思想,不过在实际高并发场景下,数组元素所消耗的空间可以忽略不计。

11CAS操作的弊端与规避措施

(1).ABA问题
解决思路:引入版本号,变量前面加上版本号,每次变量更新是将版本号加1,那么操作序列A==>B==>A就会变成A1==>B2==>A3,如果将A1当作A3的预期数据,就会操作失败。JDK提供了两个类AtomicStampedReference和AtomicMarkableReference来解决ABA问题。比较常用的是AtomicStampedReference类,该类的compareAndSet()方法的作用是首先检查当前引用是否等于预期引用,以及当前印戳是否等于预期印戳,如果全部相等,就以原子方式将引用和印戳的值一同设置为新的值。
(2).只能保证一个共享变量之间的原子性操作(当一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,CAS就无法保证原子性)
解决思路:把多个共享变量合并成一个共享变量来操作,JDK提供了AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在一个AtomicReference实例后再进行CAS操作。比如有两个共享变量i=1、j=2,可以将二者合并成一个对象,然后用CAS来操作该合并对象的AtomicReference引用。
(3).开销问题(自旋CAS如果长时间不成功(不成功就一直循环执行,直到成功)),就会给CPU带来非常大的执行开销
解决思路:以空间换时间 (1).分散操作热点 使用LongAdder 替换基础原子类,是其单个CAS热点分散到一个cells数组中。
(2)使用队列削峰,将发生CAS争用的线程加入一个队列中排列,降低CAS争用的激烈程度,JUC中非常重要的基础类AQS(抽象队列同步器)就是这么做的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python中,冒号有多种用途。首先,冒号可以用来定义代码块,例如在if语句、循环语句和函数定义中。冒号后面的缩进代码将被视为该代码块的一部分。其次,冒号还可以用来声明函数的参数和返回值的类型。这是在Python 3中引入的新特性,可以使用函数注释来标注参数和返回值的类型。最后,冒号还可以用来切片操作,用于提取列表、数组等数据结构中的一部分元素。在切片操作中,冒号前面的数字表示起始位置,冒号后面的数字表示结束位置。如果冒号前面或后面的数字为空,则表示从开头或到结尾。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [python杂记——箭头(->)和冒号(:)说明](https://blog.csdn.net/itlilyer/article/details/120633337)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [python中冒号(:)的作用](https://blog.csdn.net/weixin_46813313/article/details/113696218)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值