原子操作的实现原理

前言

之前的文章,介绍了volatile和synchronized的实现原理,然后锁中用到了大量的cas操作,那么今天我们就着重讲下cas,cas本质也是一种原子类操作。什么是原子类操作,相比大家不用我再解释了。

处理器层面的原子性

和之前的一样,单单从java层面讲述这个是没有意义的,我们需要从计算机底层来介绍这个实现。之前的volatile计算机层面的实现是通过lock指令,然后synchronized的底层实现是通过monitorenter和monitorexit指令实现的。那么今天我们介绍下,计算机是怎么实现原理类的操作的。
1.使用总线锁保证原子性:也就是锁住总线,和之前volatile的实现方式很想,但是因为锁住总线消耗比较大,所以volatile现在采用锁住缓存的方式。为什么要锁住总线呢。那是因为当多个处理器操作一个共享变量的时候,大家都会从内存读到自己的cpu缓存中,然后操作这个变量,然后再写到内存中。这样就是导致操作不是原子性的。总线锁的话,就会在总线上发出lock#信号,这样其他处理器的请求都会被阻塞住,那么这个处理器就可以独享内存。
2.使用缓存锁:这个也就是目前volatile使用的方式,这个是怎么实现原子性操作的呢。首先它不是锁住总线,它是锁住这个内存对应缓存行数据,通过缓存一致性(也就是操作系统禁止会阻止同时修改由两个以上处理器缓存的内存数据(简单的说就是一个内存可能会在多个处理器缓存中有副本,但是同一时间,只能有一个缓存被修改和写回内存,其他都会被锁定)),来保证原子性的,当其他处理器回写已被锁定的缓存行数据,会使缓存无效。
缓存锁虽然消耗比总线锁小,但是有不可用的场景
1.当操作的数据不能被缓存到处理器内部的时候,第二个就是操作的数据跨多个缓存行的时候,这种情况下,会使用总线锁定。
2.有的处理器支持缓存锁定。

java层面的原子操作

说完操作系统层面的原子操作之后,我们接着来看,java 层面的原子操作。
java实现原子操作就两种方式,一种是锁,一种是cas,但是锁的实现基本也会用到cas操作。关于cas的概念我就不再多解释了。cas底层靠的是CMPXCHG指令。自旋cas操作基本就是循环执行cas操作直到成功为止。
cas实现原子操作的三大问题
1.十分经典的aba问题。a变成b再变成a,cas会以为这个a的值没有变化过。这个解决也比较容易,加上一个版本号,就可以实现了。
2.循环时间长,开销大。这个自旋锁大家都知道,长时间自旋会很占cpu的资源的,自旋cas也是这个道理。如果jvm支持pause指令,可能会好很多。pause指令有两个作用:1.延迟流水线执行指令。2.避免退出的时候因为内存顺序冲突而引起cpu流水线清空。
3.只能保证一个共享变量的原子性操作。AtomicReference保证引用对象之间的原子性。

总结

之前的文章介绍了volitile和锁,而锁中用到了大量的cas操作。而cas又是原子类的操作,所以我们就从java层面和计算机层面讲解下原子操作的实现。这个volatile和cas在之后大量的并发工具和锁用都会用到,希望可以对之后的大家理解java的并发工具和锁的时候有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mark---小鑫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值