volatile是如何保证有序性的?
为什么需要保证有序性?
有如下代码,在int i = a;执行了的情况下,i的值最终会为几?
public class NoVolatileExample {
int a = 0;
boolean flag = false;
public void writer() {
a = 1;
flag = true;
}
public void reader() {
if (flag) {
int i = a;
}
}
}
假设现在有线程A首先执行writer()方法,然后线程B执行reader()方法,那么线程A和B执行完毕之后i一定会为1?答案是不一定,根据as-if-serial原则,对与单线程执行程序,如果执行的结果不会改变,允许重排序。那么就可能会出现以下的情况。
- 线程A 执行flag = true
- 线程B 执行if (flag)
- 线程B 执行int i = a;
- 线程A 执行a = 1;
最终结果 i = 0;和我们认为的执行结果不一样。
内存屏障介绍
为了性能优化,JVM会在不改变数据依赖性的情况下,允许编译器和处理器对指令序列进行重排序,而有序性问题指的就是程序代码执行的顺序与程序员编写程序的顺序不一致,导致程序结果不正确的问题。而加了volatile修饰的共享变量,则通过内存屏障解决了多线程下有序性问题。
内存屏障分为以下四种

volatile 内存语义的实现
下面来看看 JMM 如何实现 volatile 写/读的内存语义。为了实现 volatile 内存语义,JMM 会分别限制这两种类型的重排序类型。下表是 JMM 针对编译器制定的 volatile 重排序规则表。

举例来说,第三行最后一个单元格的意思是:在程序中,当第一个操作为普通变量的读或写时,如果第二个操作为 volatile 写,则编译器不能重排序这两个操作。
从上表我们可以看出。
- 当第二个操作是 volatile 写时,不管第一个操作是什么,都不能重排序。这个规则确保 volatile 写之前的操作不会被编译器重排序到 volatile 写之后。
- 当第一个操作是 volatile 读时,不管第二个操作是什么,都不能重排序。这个规则确保 volatile 读之后的操作不会被编译器重排序到 volatile 读之前。
- 当第一个操作是 volatile 写,第二个操作是 volatile 读时,不能重排序。
为了实现 volatile 的内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。对于编译器来说,发现一个最优布置来最小化插入屏障的总数几乎不可能。为此,JMM 采取保守策略。下面是基于保守策略的 JMM 内存屏障插入策略。
- 在每个 volatile 写操作的前面插入一个 StoreStore 屏障。
- 在每个 volatile 写操作的后面插入一个 StoreLoad 屏障。
- 在每个 volatile 读操作的后面插入一个 LoadLoad 屏障。
- 在每个 volatile 读操作的后面插入一个 LoadStore 屏障。
针对以上代码如何保证有序性?
对flag 添加volatile修饰
public class VolatileExample {
int a = 0;
volatile boolean flag = false;
public void writer() {
a = 1; // 1
flag = true; //2
}
public void reader() {
if (flag) { //3
int i = a; //4
}
}
}

根据 happens-before规则(不了解的可以先去了解一下happens-before原则),这个过程建立的 happens-before 关系可以分为 3 类:
根据程序次序规则,1 happens-before 2;3 happens-before 4。
根据 volatile 规则,2 happens-before 3。
根据 happens-before 的传递性规则,1 happens-before 4。
所有对于线程A对a的写入(a=1),b线程在执行4的时候是可见的,最终结果i=1.
volatile是如何保证有序性的?的更多相关文章
- 为什么volatile能保证有序性不能保证原子性
对于内存模型的三大特性:有序性.原子性.可见性. 大家都知道volatile能保证可见性和有序性但是不能保证原子性,但是为什么呢? 一.原子性.有序性.可见性 1.原子性: (1)原子的意思代表着-- ...
- volatile并不能保证数据同步、只能保证读取到最新主内存数据
在 java 垃圾回收整理一文中,描述了jvm运行时刻内存的分配.其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈, 线程栈保存了线程运行时候变量值信息.当线程访问某一个对象时候值的 ...
- volatile变量能保证线程安全性吗?为什么?
在谈及线程安全时,常会说到一个变量——volatile.在<Java并发编程实战>一书中是这么定义volatile的——Java语言提供了一种稍弱的同步机制,即volatile变量,用来确 ...
- Java 并发编程:volatile的使用及其原理
Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...
- Java 开发, volatile 你必须了解一下
上一篇文章说了 CAS 原理,其中说到了 Atomic* 类,他们实现原子操作的机制就依靠了 volatile 的内存可见性特性.如果还不了解 CAS 和 Atomic*,建议看一下我们说的 CAS ...
- Java多线程之三volatile与等待通知机制示例
原子性,可见性与有序性 在多线程中,线程同步的时候一般需要考虑原子性,可见性与有序性 原子性 原子性定义:一个操作或者多个操作在执行过程中要么全部执行完成,要么全部都不执行,不存在执行一部分的情况. ...
- 【Java并发编程】11、volatile的使用及其原理
一.volatile的作用 在<Java并发编程:核心理论>一文中,我们已经提到过可见性.有序性及原子性问题,通常情况下我们可以通过Synchronized关键字来解决这些个问题,不过如果 ...
- 深入理解Java中的volatile关键字
在再有人问你Java内存模型是什么,就把这篇文章发给他中我们曾经介绍过,Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized ...
- volatile的用法
在再有人问你Java内存模型是什么,就把这篇文章发给他中我们曾经介绍过,Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized ...
- 【转】Java 并发编程:volatile的使用及其原理
一.volatile的作用 在<Java并发编程:核心理论>一文中,我们已经提到过可见性.有序性及原子性问题,通常情况下我们可以通过Synchronized关键字来解决这些个问题,不过如果 ...
随机推荐
- vue前端路由的两种模式,hash与history的区别
1.直观区别: hash模式url带#号,history模式不带#号. 2.深层区别: hash模式url里面永远带着#号,我们在开发当中默认使用这个模式. 如果用户考虑url的规范那么就需要使用hi ...
- [OpenCV-Python] 10 图像上的算术运算
文章目录 OpenCV-Python: 核心操作 10 图像上的算术运算 10.1 图像加法 10.2 图像混合 10.3 按位运算 OpenCV-Python: 核心操作 10 图像上的算术运算 目 ...
- 如何通过C#/VB.NET代码将PowerPoint转换为HTML
利用PowerPoint可以很方便的呈现多媒体信息,且信息形式多媒体化,表现力强.但难免在某些情况下我们会需要将PowerPoint转换为HTML格式.因为HTML文档能独立于各种操作系统平台(如Un ...
- elSelect点击空白处无法收起下拉框(失去焦点并隐藏)
学习记录,为了以后有同样的问题,省得再百度了,方便自己也方便你们element 中多选的select 有个问题,就是点击空白或者关闭弹窗,下拉还会一直展示出来百度了好一会,觉得下面两位大佬说的最合理, ...
- OpenResty学习笔记03:再探WAF
一. 再谈WAF 我们上一篇安装的WAF来自另一位技术大神 赵舜东,花名 赵班长,一直从事自动化运维方面的架构设计工作.阿里云MVP.华为云MVP.中国SaltStack用户组发起人 .新运维社区发起 ...
- bean的作用域和@scope注解
bean的作用域由@scope注解来修改,该注解有五个不同的取值,分别是:singleton.prototype.request.session.global-session. singleton,在 ...
- Xposed框架关于无法在模拟器中下载和激活的问题
开头 最近xposed不知道出了什么问题,导致安装的时候一直在失败,所以记录下网上参考到的并用于实践中 安装软件 1.模拟器 逍遥游模拟器 安卓7.1 版本.下载地址为: https://www.52 ...
- 关于前端vue打包项目以及静态网站部署项目到阿里云ECS云服务器初学简单教程
准备工作: 1.首先进入https://ecs.console.aliyun.com/ 领取或者购买一台简单的ECS云服务器. 进入网站注册登录后拉到页面最下面或者顶部搜索免费云服务器领取立即试用 , ...
- WSGI实现支持多URL的WEB服务器
- CMD 常用命令总结
CMD 常用命令总结 小技巧: 输入 help,查看帮助: Tab 键,自动补全: 上/下方向键,查看历史命令: 右键窗口标题栏 -> 属性,可以修改外观样式. # 关机.重启.注销.休眠.定时 ...