voliate关键字的两个作用

1、 保证变量的可见性:当一个被volatile关键字修饰的变量被一个线程修改的时候,其他线程可以立刻得到修改之后的结果。当一个线程向被volatile关键字修饰的变量写入数据的时候,虚拟机会强制它被值刷新到主内存中。当一个线程用到被volatile关键字修饰的值的时候,虚拟机会强制要求它从主内存中读取。
2、 屏蔽指令重排序:指令重排序是编译器和处理器为了高效对程序进行优化的手段,它只能保证程序执行的结果时正确的,但是无法保证程序的操作顺序与代码顺序一致。这在单线程中不会构成问题,但是在多线程中就会出现问题。非常经典的例子是在单例方法中同时对字段加入voliate,就是为了防止指令重排序。

编译期重排序的典型就是通过调整指令顺序,做到在不改变程序语义的前提下,尽可能减少寄存器的读取、存储次数,充分复用寄存器的存储值。
比如我们有如下代码:
int x = 10;
int y = 9;
x = x+10;

假设编译器直接对上面代码进行编译,不进行重排序的话,我们简单分析一下执行这段代码的过程,首先加载x变量的内存地址到地址寄存器,然后会加载10到数据寄存器,然后CPU通过mov指令把10写入到地址寄存器中指定的内存地址中。然后加载y变量的内存地址到地址寄存器,加载9到数据寄存器,把9写入到内存地址中。进行第三行执行时,我们发现CPU需要重新加载x的内存地址和数据到寄存器,但如果我把第三行和第二行换一下顺序,那么执行过程中对于寄存器的存取就可以少很多次,同时对于程序结果没有任何影响。
另一个例子可以看下面的双重检查锁构造单例的代码
public class Singleton {
private volatile static Singleton singleton;

private Singleton() {}public static Singleton getInstance() {if (singleton == null) { // 1synchronized(Singleton.class) {if (singleton == null) {singleton = new Singleton(); // 2}}}return singleton;
}

}

实际上当程序执行到2处的时候,如果我们没有使用volatile关键字修饰变量singleton,就可能会造成错误。这是因为使用new关键字初始化一个对象的过程并不是一个原子的操作,它分成下面三个步骤进行:
a. 给 singleton 分配内存
b. 调用 Singleton 的构造函数来初始化成员变量
c. 将 singleton 对象指向分配的内存空间(执行完这步 singleton 就为非 null 了)
如果虚拟机存在指令重排序优化,则步骤b和c的顺序是无法确定的。如果A线程率先进入同步代码块并先执行了c而没有执行b,此时因为singleton已经非null。这时候线程B到了1处,判断singleton非null并将其返回使用,因为此时Singleton实际上还未初始化,自然就会出错。synchronized可以解决内存可见性,但是不能解决重排序问题。
但是特别注意在jdk 1.5以前的版本使用了volatile的双检锁还是有问题的。其原因是Java 5以前的JMM(Java 内存模型)是存在缺陷的,即时将变量声明成volatile也不能完全避免重排序,主要是volatile变量前后的代码仍然存在重排序问题。这个volatile屏蔽重排序的问题在jdk 1.5 (JSR-133)中才得以修复,这时候jdk对volatile增强了语义,对volatile对象都会加入读写的内存屏障,以此来保证可见性,这时候2-3就变成了代码序而不会被CPU重排,所以在这之后才可以放心使用volatile。

作者:鹅鹅鹅_
链接:https://www.jianshu.com/p/a67dc1c11088
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

voliate解决重排序相关推荐

  1. Java内存访问重排序的研究

    什么是重排序 请先看这样一段代码1 public class PossibleReordering { static int x = 0, y = 0; static int a = 0, b = 0 ...

  2. 分类变量 哑变量矩阵 指标矩阵_不懂数据集重排序?分类变量转换苦难?4种python方法,不再难!...

    前言 数据排序.分类变量转换是数据处理与分析中常常遇到对场景,且需要有准确的判断以及准确的处理方式,否则会影响数据质量,产生脏数据,进而影响数据呈现效果或预测效果等,更别提机器学习与深度学习准确性等系 ...

  3. Java之volatile如何保证可见性和指令重排序

    1 我们先了解CPU缓存 CPU缓存为了解决CPU运算速度与内存读写速度不匹配的问题,因为CPU运算速度要比内存读写速度快得多 一次主内存的访问通常在几十到几百个时钟周期 一次L1高速缓存的读写只需要 ...

  4. java volidate线程安全_03.(多线程与并发)面试题-02--Volidate的原理和指令重排序

    线程栈(线程的工作内存)保存了线程运行时候变量值信息.当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本 ...

  5. 论文浅尝 - EMNLP2020 | 通过词重排序跨语言解析

    笔记整理 | 吴林娟,天津大学硕士 来源:EMNLP2020 链接:https://www.aclweb.org/anthology/2020.findings-emnlp.265.pdf 动机 依赖 ...

  6. 为了防止程序重排序,慎用volatile

    之前在InfoQ看到一篇关于java重排序的一篇文章,觉得里面有些知识写得太绝对了,于是想通过实际程序来说明一下: 关于java重排序,这里就不做介绍了,我们知道JVM底层封装了与OS的交互,它内部有 ...

  7. ConcurrentProgramming:volatile/构造方法溢出/禁止重排序

    ConcurrentProgramming:volatile/构造方法溢出/禁止重排序 关键词 内存可见性原理(直接操作主存) 禁止指令重排原理(内存屏障,最终目的:直接操作主内存) 对volatil ...

  8. 【实践】端智能在大众点评搜索推荐重排序的应用实践

    猜你喜欢 0.2022年人才市场洞察及薪酬指南1.如何搭建一套个性化推荐系统?2.[免费下载]2022年1月份热门报告3.全民K歌推荐系统算法.架构及后台实现4.微博推荐算法实践与机器学习平台演进5. ...

  9. java重排序_Java synchronized 能防止指令重排序吗?

    @ZealTalk 说的是 synchronized 可以防止指令重排,这个观点不对的,也欢迎回答的各位来讨论 synchronized 的有序性 来讨论这个问题先,先看看 Java 里的操作无序现象 ...

最新文章

  1. Leangoo产品白皮书
  2. Jquery加载dom元素
  3. cmw500综合测试仪使用_综合布线中手持式测试仪
  4. 科大星云诗社动态20210602
  5. 通过环境变量注入的方式启动SAP Spartacus B2B模块
  6. 兼容FF,IE的纯CSS下拉菜单
  7. css复合选择器 1205
  8. 多元算力加持,华为云鲲鹏大数据服务公测上线
  9. Android系统(126)---OKHTTP
  10. nginx——ngx_http_gzip_module
  11. [ZJOI2008]生日聚会
  12. 【Beta】Scrum Meeting 3
  13. SQL server 基础语法
  14. linux dd winpe,winpe/linux多重启动
  15. android NFC getId()后进制转换
  16. 计算机的英语怎么拼读,拼音拼读怎么教
  17. [036] 微信公众帐号开发教程第12篇-符号表情的发送(下)
  18. Django企业开发实战--by胡阳,学习记录1015
  19. Java判断一个字符串是否包含某个字符
  20. android 显示进度,progressdialog-如何在Android中显示进度对话框?

热门文章

  1. 使用Canvas和JavaScript做一个画板
  2. Excel添加目录索引
  3. 给中国学生的信 -- 开复
  4. 牛客网 — [牛客小白月赛15]斑羚飞渡(贪心)
  5. 烦人的加班,我该如何提升前端技术?
  6. Icesword 驱动部分分析
  7. 7-16 哈利·波特的考试 (25分)
  8. K8Sv1.20二进制多master部署
  9. urldecode二次解析
  10. いたずら学園 免DVD 重启破解+界面汉化补丁