浅谈CAS

1.什么是CAS

在并发的时候,我认为V的值应该是A,如果是的话那我就把它改成B,如果不是A(说明被别人修改过了),那我就不修改了,避免多人同时修改导致出错。CAS有三个操作数:内存值∨、预期值A、要修改的值B,当且仅当预期值A和内存值∨相同时,才将内存值修改为B,否则什么都不做。最后返回现在的V值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Zma6ucB-1636097856684)(https://i.loli.net/2021/10/28/GvlIsXypZ8ThR4n.png)]

2.应用场景
  • ​ 乐观锁
  • ​ 并发容器
  • ​ 原子类
3.以 AtomicInteger为例,分析在Java中是如何利用CAS实现原子操作的?
  1. AtomicInteger加载Unsafe工具,用来直接操作内存数据
  2. Unsafe来实现底层操作, UnsafeCAS的核心类。Java无法直接访问底层操作系统,而是通过本地( native)方法来访问。不过尽管如此,JVM还是开了一个后门,JDK中有一个类 Unsafe,它提供了硬件级别的原子操作,valueoffset表示的是变量值在内存中的偏移地址,因为Unsafe就是根据内存偏移地址获取数据的原值的,这样我们就能通过 unsafe来实现CAS了,Unsafe类中compareAndSwapInt方法,方法中先想办法拿到变量value在內存中的地址,通过 Atomic: cmpxchg(x,address,e)实现原子性的比较和替换,其中参数x是即将更新的值,参数e是原内存的值。至此,最终完成了CAS的全过程。
  3. volatile修饰 value字段,保证可见性
4.缺点

ABA问题

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

自旋时间过长

​ 自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值