volatile保证可见性及重排序方法


Posted in Java/Android onAugust 05, 2022

一、JMM的内存可见性保证

按程序类型,Java程序的内存可见性保证可以分为下列3类:

单线程程序:单线程程序不会出现内存可见性问题。编译器、runtime和处理器会共同确保单线程程序的执行结果与该程序在顺序一致性模型中的执行结果相同。

正确同步的多线程程序:正确同步的多线程程序的执行将具有顺序一致性(程序的执行结果与该程序在顺序一致性内存模型中的执行结果相同)。这是JMM关注的重点,JMM通过限制编译器和处理器的重排序来为程序员提供内存可见性保证。

未同步/未正确同步的多线程程序:JMM为它们提供了最小安全性保障:线程执行时读取到的值,要么是之前某个线程写入的值,要么是默认值未同步程序在JMM中的执行时,整体上是无序的,其执行结果无法预知。 JMM不保证未同步程序的执行结果与该程序在顺序一致性模型中的执行结果一致。

二、volatile的内存语义

1、volatile的特性

可见性:对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性(基于这点,我们通过会认为volatile不具备原子性)。volatile仅仅保证对单个volatile变量的读/写具有原子性,而锁的互斥执行的特性可以确保对整个临界区代码的执行具有原子性。

有序性:对volatile修饰的变量的读写操作前后加上各种特定的内存屏障来禁止指令重排序来保障有序性。

volatile 写-读的内存语义:

当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。

当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,线程接下来将从主内存中读取共享变量。

2、volatile可见性实现原理

JMM内存交互层面实现:volatile修饰的变量的read、load、use操作和assign、store、write必须是连续的,即修改后必须立即同步回主内存,使用时必须从主内存刷新,由此保证volatile变量操作对多线程的可见性。

硬件层面实现:通过lock前缀指令,会锁定变量缓存行区域并写回主内存,这个操作称为“缓存锁定”,缓存一致性机制会阻止同时修改被两个以上处理器缓存的内存区域数据。一个处理器的缓存回写到内存会导致其他处理器的缓存无效。

三、指令重排序

Java语言规范规定JVM线程内部维持顺序化语义。即只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码顺序不一致,此过程叫指令的重排序。指令重排序的意义:JVM能根据处理器特性(CPU多级缓存系统、多核处理器等)适当的对机器指令进行重排序,使机器指令能更符合CPU的执行特性,最大限度的发挥机器性能。在编译器与CPU处理器中都能执行指令重排优化操作。

volatile保证可见性及重排序方法

JMM内存屏障插入策略:

  • 在每个volatile写操作的前面插入一个StoreStore屏障
  • 在每个volatile写操作的后面插入一个StoreLoad屏障
  • 在每个volatile读操作的后面插入一个LoadLoad屏障
  • 在每个volatile读操作的后面插入一个LoadStore屏障

不同硬件实现内存屏障的方式不同,Java内存模型屏蔽了这种底层硬件平台的差异,由JVM来为不同的平台生成相应的机器码。

以上就是volatile保证可见性及重排序方法的详细内容,更多关于volatile可见性重排序的资料请关注三水点靠木其它相关文章!

Java/Android 相关文章推荐
详解JAVA中的OPTIONAL
Jun 14 Java/Android
分析JVM源码之Thread.interrupt系统级别线程打断
Jun 29 Java/Android
Java org.w3c.dom.Document 类方法引用报错
Aug 07 Java/Android
Java Spring 控制反转(IOC)容器详解
Oct 05 Java/Android
java多态注意项小结
Oct 16 Java/Android
Java9新特性对HTTP2协议支持与非阻塞HTTP API
Mar 16 Java/Android
Springboot-cli 开发脚手架,权限认证,附demo演示
Apr 28 Java/Android
springboot为异步任务规划自定义线程池的实现
Jun 14 Java/Android
SpringBoot使用ip2region获取地理位置信息的方法
Jun 21 Java/Android
Spring Boot 的创建和运行示例代码详解
Jul 23 Java/Android
volatile保证可见性及重排序方法
Aug 05 Java/Android
Android实现获取短信验证码并自动填充
May 21 Java/Android
app场景下uniapp的扫码记录
Jul 23 #Java/Android
IDEA中sout快捷键无效问题的解决方法
Jul 23 #Java/Android
Spring Boot 的创建和运行示例代码详解
阿里面试Nacos配置中心交互模型是push还是pull原理解析
Jul 23 #Java/Android
java实现web实时消息推送的七种方案
前端与RabbitMQ实时消息推送未读消息小红点实现示例
springboot+rabbitmq实现智能家居实例详解
You might like
解析用PHP读写音频文件信息的详解(支持WMA和MP3)
2013/05/10 PHP
php获取URL中带#号等特殊符号参数的解决方法
2014/09/02 PHP
yii实现CheckBox复选框在同一行显示的方法
2014/12/03 PHP
php中使用url传递数组的方法
2015/02/11 PHP
PHP实现发送邮件的方法(基于简单邮件发送类)
2015/12/17 PHP
PHP编程获取音频文件时长的方法【基于getid3类】
2017/04/20 PHP
PHP中递归的实现实例详解
2017/11/14 PHP
js 图片缩放(按比例)控制代码
2009/05/27 Javascript
google地图的路线实现代码
2009/08/20 Javascript
setInterval,setTimeout与jquery混用的问题
2013/04/08 Javascript
jQuery获取CSS样式中的颜色值的问题,不同浏览器格式不同的解决办法
2013/05/13 Javascript
jquery三个关闭弹出层的小示例
2013/11/05 Javascript
深入理解javascript构造函数和原型对象
2014/09/23 Javascript
JavaScript动态修改背景颜色的方法
2015/04/16 Javascript
Jquery使用val方法读写value值
2015/05/18 Javascript
jQuery解析XML 详解及方法总结
2016/09/28 Javascript
javascript将json格式数组下载为excel表格的方法
2017/12/22 Javascript
nginx+vue.js实现前后端分离的示例代码
2018/02/12 Javascript
Vue 路由切换时页面内容没有重新加载的解决方法
2018/09/01 Javascript
JavaScript中reduce()的5个基本用法示例
2020/07/19 Javascript
如何构建一个Vue插件并生成npm包
2020/10/26 Javascript
[39:52]2018DOTA2亚洲邀请赛 4.3 突围赛 EG vs Newbee 第一场
2018/04/04 DOTA
[01:08:00]Fnatic vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python 的 Socket 编程
2015/03/24 Python
Python使用shelve模块实现简单数据存储的方法
2015/05/20 Python
Python判断telnet通不通的实例
2019/01/26 Python
python Plotly绘图工具的简单使用
2020/03/03 Python
python 字典item与iteritems的区别详解
2020/04/25 Python
matplotlib交互式数据光标mpldatacursor的实现
2021/02/03 Python
美国派对用品及装饰品网上商店:Shindigz
2016/07/30 全球购物
法国购买隐形眼镜和眼镜网站:Optical Center
2019/10/08 全球购物
Fabletics官网:美国运动服饰品牌,由好莱坞女演员凯特·哈德森创立
2019/10/19 全球购物
师德师风个人总结
2015/02/06 职场文书
开学随笔
2015/08/15 职场文书
python基于opencv批量生成验证码的示例
2021/04/28 Python
新的CSS 伪类函数 :is() 和 :where()示例详解
2022/08/05 HTML / CSS