Java并发篇:volatile为什么不能多条保证原子性 ?volatile为什么能保证单条原子性?

我个人总结理解的两方面影响:

简单举例说明,就不用看下面详细解释了:

i=0; A,B2个线程各i++ 50000次
1.线程A 读到i=0时,A阻塞,B也读到i=0,进行i++ 写到主存,此时i=1,A继续执行进行i++,i=1写回主存。
2.MESI协议中,AB线程同时进行修改i,此时裁决机制进行裁决设缓存A为M状态,缓存B为I状态,那么B线程修改无效,并且浪费一次,A进行i++把i=1写回主存。

分别执行三次,每次结果各不相同:

输出最后结果:93873

输出最后结果:80319

输出最后结果:95797

第一方面(无法保证多条指令原子性)

假设线程A首先读取到了i的0,进行+1操作,但是还没来得及更新,就阻塞了,这时线程B开始了,他也读取到i的值,由于i的值未被更新,即使是被volatile修饰,主存的变量还没变化,那么线程B得到的值也是0,之后对其进行加1操作,得到i=1后,将新值写入到缓存中,再刷入主存(此时主存i由0变为1)中。

此时如果A线程被唤醒,A线程将继续执行更新操作,写入到缓存中,再输入到主存中(此时主存i由1变为1),多次线程竞争阻塞导致多次浪费,所以达不到预期100000

总结来说:

i++操作是非原子操作,i++的过程分三步,首先获取i的值,其次对i的值进行加1,最后将得到的新值写会到缓存中。你说的emsi确实导致了缓存行失效,但是这三步如果已经进行了两步,第三步的时候如果其他线程更改了值,你察觉到了也没用,你已经读过赋过值了。

第二方面(可保证单条指令原子性和可见性)

因为volatile底层使用的是缓存一致性协议,会根据MESI原则。

MESI分别代表缓存行数据所处的四种状态,通过对这四种状态的切换,来达到对缓存数据进行管理的目的。

M 修改 Modified : 该缓存行有效,且该缓存行数据被修改了,和内存中的数据不一致,数据只存在于本缓存行中,此时状态为M ;


E 独占 Exclusive : 该缓存行有效,且该缓存行数据和内存中的数据一致,此时状态为E;


S 共享 Shared : 该缓存行有效,且该缓存行数据和内存中的数据一致,数据同时存在于其他缓存中(同步到主内存中完成后 , 标记为共享状态 ; 共享状态的变量才能被线程加载到工作内存中),此时状态为S ;


I 失效 Invalid : 该缓存行无效,线程 A , B 中都使用了同一个共享变量 , 如果在线程 A 中修改该变量 , 线程 B 中的变量更新前都标记为失效状态,此时A状态为M状态,B状态为I状态 ;

1、CPU1从内存中将变量i加载到缓存中,并将变量i的状态改为E(独享),并通过总线嗅探机制对内存中变量i的操作进行嗅探(因为有volatile关键字修饰,如果没有修饰则不会进行嗅探,说明可见性)

2、此时,CPU2读取变量i,总线嗅探机制会将CPU1中的变量i的状态置为S(共享),并将变量i加载到CPU2的缓存中,状态为S

 3、CPU1对变量i进行修改操作,此时CPU1中的变量i会被置为M(修改)状态,而CPU2中的变量i会被通知,改为I(无效)状态,此时CPU2中的变量i做的任何修改都不会被写回内存中(高并发情况下可能出现两个CPU同时修改变量i,并同时向总线发出将各自的缓存行更改为M状态的情况,此时总线会采用相应的裁决机制进行裁决,将其中一个置为M状态,另一个置为I状态,且I状态的缓存行修改无效)

4、CPU1将修改后的数据写回内存,并将变量i置为E(独占)状态 

5、此时,CPU2通过总线嗅探机制得知变量i已被修改,会重新去内存中加载变量i,同时CPU1和CPU2中的变量i都改为S状态

这就是完整的MESI流程,因为第3步中,高并发竞争总线会采用相应的裁决机制进行裁决,将其中一个置为M状态,另一个置为I状态,且I状态的缓存行修改无效,浪费一次i++,所以i也达不到100000。

第三方面(单条指令的内存模型保证单条数据的原子性)

Ø ·在每个volatile 写操作的前面 插入一个 StoreStore 屏障。
Ø ·在每个volatile 写操作的后面 插入一个 StoreLoad 屏障。

Ø ·在每个 volatile读操作的 后面 插入一个 LoadLoad 屏障。
Ø ·在每个 volatile读操作的 后面 插入一个 LoadStore 屏障。

最后,如果文章有问题留言反馈,会及时更改,以免误导他人,

如果觉得有帮助,请帮忙点个赞!感谢!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值