Java虚拟机内存模型和volatile型变量
Java虚拟机内存模型
了解Java虚拟机的内存模型,有助于我们明白为什么会发生线程安全问题.
上面这幅图是<深入理解Java虚拟机-JVM高级特性与最佳实践>的书中截图.
线程共享的变量会保存在主内存中(Main Memory).
而线程共享的变量的副本会保存在每个线程各自的工作内存中(Working Memory).
线程对于共享变量的所有操作(读取,赋值等)都必须在工作内存中进行,不能直接读写主内存的变量.
不同的线程之间,也无法访问其他线程的工作内存.线程之间的变量传递需要通过主内存来完成.
所以发生线程安全问题的根源就在于,当共享变量在主内存中被修改后,有的线程的工作内存保存的还是该被修改的共享变量的旧的值,就导致了数据不一致的后果.
Volatile型变量
被Volatile修饰的变量,是轻量化的解决部分线程安全问题的方法,它具有2种特性:
1. 保证此变量对于所有线程的可见性,指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的.
但是这里所说的立即得知,也并不能保证Volatile就能完全避免线程安全数据一致的问题.
private volatile int race = 0; private void increase() {
race++;
}
比如上面代码,如果多线程的调用increase()方法,是并不能保证线程安全,而且是很有可能发生数据不一致的问题.
原因在于,虽然volatile保证了race变量的修改被其他线程立即得知,但是本身race++这行代码并不是原子操作.实际代码编译后会变成多条字节码.
volatile的使用场景需要符合2条规则:
1) 运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值;
2) 变量不需要与其他的状态变量共同参与不变约束.
volatile型变量的经典使用场景是如下这种.当doSomthing()方法被多线程调用时候,只需把shutDown=true之后,所有线程就不会在进行下一轮的while.
private volatile boolean shutDown = false; private void doSomething() {
while (!shutDown) {
// do something
}
}
2. 使用Volatile变量能禁止指令重排序.
普通的变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致.因为在一个县城的方法执行过程中无法感知到这点.
public VolatileExample {
Map configOptions;
char[] configText;
volatile boolean initiallized = false; private void init() {
configOptions = new HashMap();
configText = readonfigFile(fileName);
processConfigOptions(configText, configOptions);
initialized = true;
} private void do() {
while (!initialized) {
sleep();
}
doSomethingWithconfig();
}
}
上面这段代码,假设init()方法和do()方法运行再不同的线程中.如果initialized变量没有使用volatile修饰的话,init()方法可能由于指令重排序的优化(指令重排序是机器级的优化操作,提前执行时指这句话对应的汇编代码会被提前执行),导致最后一句代码initialized=true被提前执行.这种情况的后果就是do()方法因为initialized=true就跳过了while循环去执行doSomethingWithConfig()了,但其实可能init()的方法还未运行结束.
而volatile关键字可以避免此类情况的发生.
Java虚拟机内存模型和volatile型变量的更多相关文章
- Java线程角度的内存模型和volatile型变量
内存模型的目标是定义程序中各个变量的访问 规则,即在虚拟机中将变量(包括实例字段,静态字段和构成数组对象的元素,不包括局部变量与方法参数,因为后者是线程私有的)存储到内存和从内存中取出变量这样的底层细 ...
- 并发一:Java内存模型和Volatile
并发一:Java内存模型和Volatile 一.Java内存模型(JMM) Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和在内存中取出变量的底层细节,是围绕着 ...
- 黑马-----内存模型和volatile详解
黑马程序员:Java培训.Android培训.iOS培训..Net培训 JAVA线程-内存模型和volatile详解 一.单核内存模型 1.程序运行时,将临时数据存放到Cache中 2.将CPU计算所 ...
- JAVA内存模型和Happens-Before规则
前言 上一篇文章王子给大家介绍了并发编程中比较关心的三个核心问题,可见性.有序性和原子性. 今天我们继续来探索并发编程的内容,聊一聊JAVA的内存模型和Happens-Before规则. JAVA内存 ...
- Java内存模型和JVM内存管理
Java内存模型和JVM内存管理 一.Java内存模型: 1.主内存和工作内存(即是本地内存): Java内存模型的主要目标是定义程序中各个变量的访问规则,即在JVM中将变量存储到内存和从内存中取 ...
- 【Java】JMM内存模型和JVM内存结构
JMM内存模型和JVM内存结构 JAVA内存模型(Java Memory Model) Java内存模型,一般指的是JDK 5 开始使用的新的内存模型,主要由JSR-133: JavaTM Memor ...
- Java 内存模型和 JVM 内存结构真不是一回事
这两个概念估计有不少人会混淆,它们都可以说是 JVM 规范的一部分,但真不是一回事!它们描述和解决的是不同问题,简单来说, Java 内存模型,描述的是多线程允许的行为 JVM 内存结构,描述的是线程 ...
- JVM内存结构、Java内存模型和Java对象模型
Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点.而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚.比如本文要讨论的JVM内存结构.Java内存模型和Java对象模型 ...
- Java内存模型和ConcurrentHashMap 1.7源码分析
简介 ConcurrentHashMap 是 util.concurrent 包的重要成员.本文将结合 Java 内存模型,分析 JDK 源代码,探索 ConcurrentHashMap 高并发的具体 ...
随机推荐
- EXCEL 处理重复数据名字后面追加值
近期要用 EXCEL 处理重复数据名字后面追加值的,如图: 先排序,再根据条件追加 [公式]=+B6&IF(COUNTIF($B$6:B6,B6)-1>0,"_" & ...
- checkpoint process vs writer process vs wal writer process
开始 我目前的理解是: 如果我执行了一条SQL文,那么 先是相关数据写到 wal buffer里, 然后再写到 data buffer(shared_buffer)里. 这之后, 由于wal wr ...
- 【转载】从零实现3D图像引擎:(1)环境配置与项目框架
原文:从零实现3D图像引擎:(1)环境配置与项目框架 0. 要学懂3D程序设计,必然要精通3D相关的线性代数.3D几何.复分析等相关知识,我也因为如此才开始这个博客系列的写作,不自己实现,就不是自己的 ...
- 4709: [Jsoi2011]柠檬
4709: [Jsoi2011]柠檬 https://www.lydsy.com/JudgeOnline/problem.php?id=4709 分析: 决策单调性+栈+二分. 首先挖掘性质:每个段选 ...
- HTTP请求方式:GET和POST的比较
GET和POST是HTTP的两个常用方法 什么是HTTP? 超文本传输协议(HyperText Transfer Prptocol-HTTP)是一个设计来使客户端和服务器顺利进行通讯的协议. HTTP ...
- javaweb(二十六)——jsp简单标签标签库开发(二)
一.JspFragment类介绍 javax.servlet.jsp.tagext.JspFragment类是在JSP2.0中定义的,它的实例对象代表JSP页面中的一段符合JSP语法规范的JSP片段, ...
- 英特尔® 实感™ 摄像头 (F200) 应用如何实现最佳用户体验
英特尔开发人员专区原文 由于视频不能直接嵌入, 请点击视频标题观看.谢谢. 英特尔® 实感™ 技术支持我们重新定义如何与计算设备交互,包括允许用户通过手势自然交互. 为了帮助大家了解使用英特尔® 实感 ...
- HDU-6315:Naive Operations(线段树+思维)
链接:HDU-6315:Naive Operations 题意: In a galaxy far, far away, there are two integer sequence a and b o ...
- YAML 基础
YAML 基础 简介 对象 数组 常量 引用 1. 简介 YAML 是专门用来写配置文件的语言,非常简洁和强大! 它的基本语法规则有: 大小写敏感: 使用缩进表示层级关系: 缩进时不允许使用 Tab ...
- Spark Shell Examples
Spark Shell Example 1 - Process Data from List: scala> val pairs = sc.parallelize( List( ("T ...