java关键字volatile内存语义详细分析

volatile内存语义的实现
JMM会限制编译器重排序和处理器对volatile语义重排序。
volatile重排序规则表:

1.当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序。这个规则确保 volatile写 之前的操作不会被编译器重排序到volatile写之后。
2.当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。这个规则确保 volatile读之后的操作不会被编译器重排序到volatile读之前。
3.当第一个操作是volatile写,第二个操作是volatile读时,不能重排序。
为了实现volatile内存语义,编译器会在指令序列插入内存屏障来限制指令重排序。下面是基于保守策略的JMM内存屏障插入策略(关于内存屏障指令见文章末尾介绍):
1.在每个volatile写操作的前面插入一个StoreStore屏障。
2.在每个volatile写操作的后面插入一个StoreLoad屏障。
3.在每个volatile读操作的后面插入一个LoadLoad屏障。
4.在每个volatile读操作的后面插入一个LoadStore屏障。
volatile写插入内存屏障后生成的指令序列示意图:

这里比较有意思的是,volatile写后面的StoreLoad屏障。此屏障的作用是避免volatile写与 后面可能有的volatile读/写操作重排序。因为编译器常常无法准确判断在一个volatile写的后面 是否需要插入一个StoreLoad屏障(比如,一个volatile写之后方法立即return)。为了保证能正确 实现volatile的内存语义,JMM在采取了保守策略:在每个volatile写的后面,或者在每个volatile 读的前面插入一个StoreLoad屏障。从整体执行效率的角度考虑,JMM最终选择了在每个 volatile写的后面插入一个StoreLoad屏障。因为volatile写-读内存语义的常见使用模式是:一个 写线程写volatile变量,多个读线程读同一个volatile变量。当读线程的数量大大超过写线程时, 选择在volatile写之后插入StoreLoad屏障将带来可观的执行效率的提升。
volatile读插入内存屏障后生成的指令序列示意图:

上述volatile写和volatile读的内存屏障插入策略非常保守。在实际执行时,只要不改变 volatile写-读的内存语义,编译器可以根据具体情况省略不必要的屏障。下面通过具体的示例 代码进行说明。

针对readAndWrite()方法,编译器在生成字节码时可以做如下的优化。

内存屏障类型表:

java关键字volatile内存语义详细分析的更多相关文章
- java多线程03-----------------volatile内存语义
java多线程02-----------------volatile内存语义 volatile关键字是java虚拟机提供的最轻量级额的同步机制.由于volatile关键字与java内存模型相关,因此, ...
- java 关键字volatile
一.Java内存模型 想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的. Java内存模型规定了所有的变量都存储在主内存中.每条线程中还有自己的工作内存,线程的工作 ...
- 深入汇编指令理解Java关键字volatile
volatile是什么 volatile关键字是Java提供的一种轻量级同步机制.它能够保证可见性和有序性,但是不能保证原子性 可见性 对于volatile的可见性,先看看这段代码的执行 flag默认 ...
- JAVA关键字Volatile的特性
一.简述: 关键字Volatile是JAVA虚拟机提供的最轻量级的同步机制,但是它并不容易完全被正确.完整的理解,以致于许多程序员在遇到需要处理多线程数据竞争的时候一律使用synchronized来进 ...
- volatile内存语义
全面理解Java内存模型(JMM)及volatile关键字 volatile的内存语义 Volatile读写所建立的happens-before关系Volatile读写的内存语义 锁: 获取和释放Vo ...
- Java 关键字volatile的解释
volatile 关键字特征: 1.可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的.可以禁止线程的工作内存对volatile修饰的变量进行缓存,并将修改的变量立即写入主存. 2. ...
- Java关键字-volatile
关键字volatile可以说是Java虚拟机提供的最轻量级的同步机制. 一旦某个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1.保证了不同线程对这个变 ...
- 内存屏障和volatile内存语义的实现
趁周末,把以前的书拿出来,再翻一番,顺便做个笔记: 内存屏障:用来控制和规范cpu对内存操作的顺序的cpu指令. 内存屏障列表: 1.loadload:确保“前者数据装载”先于“后者装载指令”: 2. ...
- 关于 Java 关键字 volatile 的总结
1 什么是 volatile volatile 是 Java 的一个关键字,它提供了一种轻量级的同步机制.相比于重量级锁 synchronized,volatile 更为轻量级,因为它不会引起线程上下 ...
随机推荐
- LeetCode刷题 DFS+回溯
一.DFS介绍 二.LeetCode 实战 LC 17. 电话号码的字母组合 解法思路 解题步骤 代码 LC 79. 单词搜索 解题思路 解题步骤 代码 LC 46. 全排列 解题思路一 解题步骤 代 ...
- MAC电脑如何将常规视频中音频提取出来(转换格式并调整采样频率),并利用讯飞语音识别文字
1.下载好相关视频 2.选中需要提取视频,鼠标右键找到「编码所选视频文件」 3.设置中,下拉选择「仅音频」,点击继续 4.找到已提取成功的音频,鼠标右键或快捷键「command + I」,显示简介.默 ...
- Intellij IDEA 配置Junit
导包: 1.Hamcrest Core 包: https://mvnrepository.com/artifact/org.hamcrest/hamcrest-core/1.3 2.Junit包 ...
- 大一C语言学习笔记(9)---指针篇--从”内存的使用“和“流程控制”的角度来理解“指针变量的使用‘
#深入理解指针变量 举个错误栗子: //以下代码的目的是输出100和1000,但输出结果只有一个100 #include<stdio.h> #include<malloc.h> ...
- Java学习(十一)
今天学习了this和static关键字,这两个都是c++中学过的,但讲师还是讲了2个小时... 学得东西大部分都知道吧. this是当前对象的地址,类中带有static的方法不能使用this. 类中带 ...
- [hdu7042]二叉树
考虑最后这棵二叉树的结构,不难发现被移动的点在原树或新树中构成的都是若干棵完整的子树 (若$x$被移动,则$x$在原树或新树的子树中所有点都会被移动) 先在原树中考虑此问题,对于每一棵由被移动的点所构 ...
- [bzoj2400]Optimal Marks
首先肯定每一位单独考虑,对于每一位,源点连向该位点权为0的节点inf的边,点权为1的节点连向汇点inf的边,每一条无向边拆成两条流量为1的有向边,跑最小割. 考虑一组割,一定将原图划分成源点和汇点两部 ...
- Svelte入门——Web Components实现跨框架组件复用
Svelte 是构建 Web 应用程序的一种新方法,推出后一直不温不火,没有继Angular.React和VUE成为第四大框架,但也没有失去热度,无人问津.造成这种情况很重要的一个原因是,Svelte ...
- 还有这种好事!netty自带http2的编码解码器framecodec
目录 简介 Http2FrameCodec Http2Frame.Http2FrameStream和Http2StreamFrame Http2FrameCodec的构造 Stream的生命周期 流控 ...
- 【JavaSE】格式化输出
Java格式化输出 2019-07-06 11:35:55 by冲冲 1. 输出字符串 %s 1 /*** 输出字符串 ***/ 2 // %s表示输出字符串,也就是将后面的字符串替换模式中的%s ...