前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于 Java volatile 的随笔记

关于 Java volatile 的随笔记

作者头像
星尘的一个朋友
发布2020-11-25 15:12:38
2960
发布2020-11-25 15:12:38
举报
文章被收录于专栏:星尘的一个朋友

今天偶然见到一位群友的问题

synchronized 是怎么保证可见性的?

先说一下这个问题的答案,

java 在锁释放的时候,通过jmm将缓存中的值, 刷新到内存当中, 以此来保证了数据的可见性

其实这个问题, 我们在群里延伸了很多内容, 从JMM到MESI, 从 Java 代码到汇编指令. 因为讨论的内容较多较深, 固有这篇随笔记, 这一切要感谢提出 synchronized是怎么保证可见性的这位同学;

今天讨论的内容主要就是围绕 volatile 展开的, 主要的是讨论了一下 volatile 的实现, 对于 volatile 的实现, 这里有一个很好的文章来理解 @何登成 的《C/C++ volatile 关键字剖析》

在 C/C++ 中,volatile具有易变性,是因为当读取 volatile 关键字修饰的变量的时候,不会读取寄存器的值,而是通过缓存重新加载到寄存器,然后再去读取这个值。同时volatile关键字还具有不可优化的特性,主要体现在不可用常量替换。必须要取缓存中读取寄存器在使用。接下来的就是 volatile 关键字的顺序性问题,在 C/C++中, 普通操作与volatile操作可能出现乱序的情况. 而 volatile操作与volatile操作在不同的处理器情况下, 仍然可能出现乱序的情况. 这是因为 cpu 要对指令优化可能进行排序, 在 x86 上, 读指令就有可能提前到写指令之前. storeload 乱序.

volatile 的顺序性问题, 在 C/C++中对于不同的处理器, 仍然会出现乱序的情况, volatile 决定不了. (解决的办法就是实现顺序一致规则 happends-before 语义)


Java 中, volatile 关键字继承了 C/C++中的可见性之外, 又进行了一个操作, 使得 volatile 关键字拥有了顺序性. 那就是内存屏障. 最关键的就是 StoreLoad 屏障, 解决了在X86处理器上的写读重排序的问题

X86处理器仅会对写-读操作做重排序。X86不会对读-读、读-写和写-写操作做重排序

在 Java 层面, 虚拟机通过插入内存屏障来实现 volatile, 这部内容可以在虚拟机源码中 OrderAccess 类中找到, 一共是4个方法, 分别对应到4个内存屏障中.

而在CPU层面, 具体的执行则是使用了 Lock 前缀指令关于 Lock 前缀的指令作用

关于 Lock 前缀, 这里简单总结一下. 在执行前增加 Lock 前缀

  1. 保证了对内存操作的原子性 (通过锁内存总线来实现, 这样会使所有处理器无法访问内存数据. 所以还有另外一种情况, 即所需要操作的数据在带有 Lock 前缀指令执行之前就已经被持有该缓存行的处理器锁定, 则不会通过锁总线来完成这步指令, 因为此时的数据无法被其他处理器读取, 该操作成为缓存锁定 . 但当处理器竞争程度较高, 或指令内存地址未对齐时, 仍会锁住总线)
  2. 禁止重排序
  3. 写入缓存的值刷新到主内存中
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/09/05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档