volatile与重排序
使用关键字volatile可以禁止代码的重排序;
在Java程序运行时,JIT(即使编译器)可以动态地改变程序代码运行地顺序;例如,有如下代码:
A代码-重耗时
B代码-轻耗时
C代码-重耗时
D代码-轻耗时
在多线程环境下,JIT有可能进行代码重排序,重排序后地代码顺序有可能如下:
B代码-轻耗时
D代码-轻耗时
A代码-重耗时
C代码-重耗时
这样做地主要原因是CPU流水线是同时执行这4个指令的,那么轻耗时的代码在很大程度上先执行完成,以让出CPU流水线给其他指令,所以代码重排序是为了追求更高的程序运行的效率;
重排序发生在没有依赖关系时,例如,对于上面的A,B,C,D代码,B,C,D代码不依赖A代码的结果,C,D代码不依赖A,B代码的结果,D代码不依赖A,B,C代码的结果,这种情况下就会发生重排序,如果代码之间有依赖关系,则代码不会重排序;
使用关键字volatile可以禁止代码重排序,例如,有如下代码:
A变量的操作
B变量的操作
volatile Z变量的操作
C变量的操作
D变量的操作
那么会有4种情况发生:
- A,B可以重排序
- C,D可以重排
- A,B不可以重排到Z的后面
- C,D不可以重排到Z的前面
换言之,变量Z是一个屏障,Z变量之前或之后不可以跨越Z变量,这就是屏障的作用,关键字synchronized具有同样的特性;
1.关键字synchronized之前的代码不可以重排到synchronized之后
2.关键字synchronized之后的代码不可以重排到synchronized之前
使用双重检查锁实现多线程环境下的延迟加载单例模式
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
使用volatile修饰变量singleton使该变量在多个线程间达到可见性,另外也禁止了singleton = new Singleton()的代码重排序,singleton = new Singleton()代码在内部分为3部分:
1.memory = allocate(); //分配对象的内存空间
2.ctorInstance(memory); //初始化对象
3.instance = memory; //设置instance指向刚分配的内存地址
在一些JIT编译器上,这种指令重排是真实发生的;
1.memory = allocate(); //分配对象的内存空间
3.instance = memory; //设置instance指向刚分配的内存地址
2.ctorInstance(memory); //初始化对象
所有线程在执行Java程序时都必须要遵守intra-thread semantics;intra-thread semantics保证重排序不会改变单线程内的程序结果;换句话说,intra-thread semantics允许那些在单线程内,不会改变单线程程序执行结果的重排序;

当线程A,线程B执行时,B线程访问instance所引用的对象,但这个对象没有被线程A初始化,线程B将看到一个还没有被初始化的对象;
这里的A2和A3虽然重排序了,但Java内存模型的intra-thread semantics将确保A2一定会排在A4前面执行;因此,线程A的intra-thread semantics没有改变,但A2和A3的重排序,将会导致线程B判断instance实例不为空,线程B接下来将访问instance引用的对象(上图中线程B中的虚线),此时线程B访问到的是一个没有没有初始化的对象(没有进行赋值的对象),返回的是一个空的对象;
volatile与重排序的更多相关文章
- Jvm 中的 重排序、主存、原子操作
一.重排序 好处:重排序可以提升性能,避免在一个耗时很长的指令在“执行”阶段呆很长时间,而导致后续的指令都卡在“执行”之前的阶段上. 坏处:重排序对多线程的影响 class ReorderExampl ...
- Java的多线程机制系列:不得不提的volatile及指令重排序(happen-before)
一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...
- Java的多线程机制系列:(四)不得不提的volatile及指令重排序(happen-before)
一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专 ...
- 关于volatile的可见性和禁止指令重排序的疑惑
在学习volatile语义的可见性和禁止指令重排序的相关测试中,发现并不能体现出禁止指令重排序的特性 实验代码如下 package com.aaron.beginner.multithread.vol ...
- 不得不提的volatile及指令重排序(happen-before)
微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...
- 多线程学习:Volatile与Synchronized的区别、什么是重排序
java线程的内存模型 java的线程内存模型中定义了每个线程都有一份自己的共享变量副本(本地内存),里面存放自己私有的数据,其他线程不能直接访问,而一些共享变量则存在主内存中,供所有线程访问. 上图 ...
- java并发编程的艺术(二)---重排序与volatile、final关键字
本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...
- 原子性、内存可见性和重排序——重新认识synchronized和volatile
一.原子性 原子性操作指相应的操作是单一不可分割的操作.例如,对int变量count执行count++d操作就不是原子性操作.因为count++实际上可以分解为3个操作:(1)读取变量count的当前 ...
- 单例模式+volatile禁止指令重排序
单例模式: 单例,顾名思义就是只能有一个.不能再出现第二个.就如同地球上没有两片一模一样的树叶一样. 在这里就是说:一个类只能有一个实例,并且整个项目系统都能访问该实例. 单例模式共分为两大类: 懒汉 ...
随机推荐
- Linux下rm操作误删恢复
1.查看被误删的分区 df /home/Java/... 一直到刚刚被误删的文件的路径下 2.在debugfs打开分区 open /dev/ssl 最好这个分区可能不一样,根据上 ...
- Docker之使用Dockerfile创建定制化镜像(四)
Dockerfile简介 镜像的定制实际上就是定制每一层所添加的配置.文件.如果我们可以把每一层修改.安装.构建.操作的命令都写入一个脚本,用这个脚本来构建.定制镜像,那么哪些无法重复的问题.镜像构建 ...
- Git裸仓库的分支(Active Branch)切换
Git裸仓库的Active Branch切换方法 在服务器上通过init --bare创建了一个裸仓库作为远程仓库使用,并且存在三个分支(master/kid/develop),但在使用中发现代码虽然 ...
- gRPC-go 入门(1):Hello World
摘要 在这篇文章中,主要是跟你介绍一下gRPC这个东西. 然后,我会创建一个简单的练习项目,作为gRPC的Hello World项目. 在这个项目中,只有很简单的一个RPC函数,用于说明gRPC的工作 ...
- 在Ubuntu下部署Flask项目
FlaskDemo 命名为test.py # coding=utf-8 from flask import Flask app = Flask(__name__) @app.route("/ ...
- Mysql探索之Explain执行计划详解
前言 如何写出效率高的SQL语句,提到这必然离不开Explain执行计划的分析,至于什么是执行计划,如何写出高效率的SQL,本篇文章将会一一介绍. 执行计划 执行计划是数据库根据 SQL 语句和相关表 ...
- Spark 模型选择和调参
Spark - ML Tuning 官方文档:https://spark.apache.org/docs/2.2.0/ml-tuning.html 这一章节主要讲述如何通过使用MLlib的工具来调试模 ...
- Python-变量、变量作用域、垃圾回收机制原理-global nonlocal
变量实现原理决定了Python使用的垃圾回收机制为变量引用计数,当这个对象引用计数为0时候,则会自动执行__del__函数回收资源, del方法只是把变量指向的对象引用计数减一而已并删除这个变量 表达 ...
- SQLMAP注入Access数据库
今天偶遇一Access数据库 1.首先尝试是否存在注入点,and1=1,and 1=2,发现返回信息不一样 2.使用sqlmap脱裤,发现时Access数据库,不能提权, 3.那就直接暴库吧,sqlm ...
- visual studio 2015 Opencv4.0.1配置
最近由于工作需要,要配置opencv,我的电脑vs的version是2015,在网上下载了最新的opencv 4.0.1 自己摸索总是很困难,网上的例子也比较多,但版本比较低,也不确定适不适合vs20 ...