从java中的 AtomicInteger去看cas

我们在之前的文章中介绍过原子性问题。当时我们说过使用synchnorized关键字就可以保证安全。今天我们看看java中为我们提供的另一种实现原子类。我们也AtomicInteger 为例去看看源码。

AtomicInteger

先看这货的几个属性。unsafe是啥? valueOffset又是干什么的。我们放到后续再聊。

通过上面的代码我们清晰的知道这个value 就是存储这个对象当前的current Value。我们再看看下面的代码

下面我们来看看这个AtomicInteger是如何实现原子性操作的,请看图

又是cas操作。那什么是cas呢?它现在似乎已经是一座我们不解决就无法继续前进的路障。直接找到该方法在jvm中的实现位置在

/openjdk/hotspot/src/os_cpu/linux_x86/vm/下,我们可以通过逻辑简单的看出,其会根据是否为多核cpu来判断是否进行加锁。

最后会执行cmpxchg指令。

总之我们可以得出一个结论就是cas操作可以说是java调用c ,通过c使用汇编指令调用cpu实现的操作。那我们下面就从理论的角度来看看为什么cas操作能保证原子性问题。

CPU架构

前文已经描述过cpu缓存存在的来由是因为cpu的运算速度远远大于内存的处理速度。所以我们会存在多级缓存。每个cpu运算时数据都存在自己的缓存内,而为了保证原子性。cpu实现了和总线锁定内存锁定

总线锁定:就是使用处理器提供的一个#lock信号。当一个处理器在总线上输出次信号时,其他处理器请求将被阻塞。该处理器可以独占共享内存

缓存锁定:即如果共享变量被处理器缓存在缓存行中。当它执行锁操作回写到内存时,则不会在总线上输出#lock信号,而是直接修改内部存在的地址,通过mesi保证其他处理器内该共享变量不被同时修改。

通过上面的原理我们可以理解cas操作是如何实现原子操作了。那cas和我们的锁比较有哪些优势呢,首先cas锁是非阻塞的即使失败会使用自旋重复尝试。而synchronized 是阻塞的。并且在抢锁较少的环境下,消耗的资源比加锁少的多。

可是cas也有三个臭名昭著的问题

第一其只能保证一个共享变量的原子操作

第二自旋时间过长会造成cpu资源的大量消耗

第三aba问题 (其中java的 AtomicStampedReference 就是为了解决这个问题。)

今天的总结就到这里 欢迎大家指正问题 !!  与君共勉

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值