【JVM】为什么volatile有可见性,有序性,但没有原子性

6 篇文章 0 订阅

关于synchronized的“有可见性,原子性,有序性”的实现,可以看我另外一篇文章:https://blog.csdn.net/qq_35590091/article/details/106986641

可见性

当一个变量被定义为volatile,它将具备两个特性,第一个是保证变量对所有线程具有“可见性”,具体来说就是当一个线程对该变量进行了修改,那么别的线程会立即得知(这个变化)。

那么可见性的实现原理是什么呢?

实现原理:如果使用这个修饰符,对该变量进行写操作之后,会立即执行store和write操作(对应的汇编代码中会加上一个lock前缀),立即将该变量从工作内存(或者说缓存)写入主内存,保证了对别的线程立即可见(因为这会导致别的线程的工作内存中该变量的缓存会失效),并且同时其他的cpu的工作内存中的值无效,直接从主内存读取并刷新工作内存。


有序性

  第二个特征是禁止指令重排序优化,也就是保证volatile修饰的变量不会被指令重排序优化,从而保证代码的执行顺序和程序顺序相同,保证了有序性。实现是当变量被声明为volatile时,通过在生成的字节码中插入“内存屏障”,来禁止特定类型的指令重排序(定义了很多情况下禁止指令重排序)。

举个例子:每个volatile变量在写操作之前会有一个“写写屏障”,这表示这个写操作之前的写操作和它禁止重排序,后面会有一个“写读屏障”,这表示这个写操作和后面的读操作不能重排序。

此外,关于有序性的更为详细的说明,可以看我的另外一篇博客:https://blog.csdn.net/qq_35590091/article/details/106470826


原子性

但volatile关键字不保证对变量操作的原子性(synchronized可以保证原子性)比如i++操作,这不是一个原子操作,它包括四个字节码指令,首先把i放到操作数栈栈顶,然后把int类型1放到栈顶,两个出栈相加,再入栈;而如果相加之前别线程修改了i的值,栈顶的i就是过期的,会发生错误。因此线程不安全。

也因此,使用volatile而不会引起线程不安全的前提是:1、对该变量的运算不依赖于该变量的值,或者只有一个线程能修改该变量的值。2、变量不需要与其他状态变量共同参与不变约束。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值