好吧,这里我只想说说volatile在JMM中的语义。
当我们在使用volatile的时候,实际上它表达了下面那么些意思。
1. 可见性。
这个是大多数人都知道的一个特质, JAVA的线程有自己的工作内存区,与主存区不同,当我们对变量使用了volatile后,那么不管对这个变量的读或写,都会在主存中进行,而不会在处理器的缓存或者寄存器中进行。这个很好理解。
2. 禁止CPU指令的重排序
这个特质的理解稍微要花点脑细胞, 首先我们需要一点premilinary, 当我们的程序编写好了以后,会被翻译成指令集并被加载到内存中去运行。但是,在CPU真正执行的时候,处于性能方面的考虑,这些指令的执行不一定会按照程序中的顺序进行,只要保证其程序执行语义没有变化即可。
来看下代码,
class VolatileExample {
int x = 0;
volatile boolean v = false;
//in thread A
public void writer() {
x = 42;
v = true;
}
//in thread B
public void reader() {
if (v == true) {
//uses x - can we see x is 42?
}
}
}
在这种情况下,当thread A 执行完后,在thread B中能看到x等于42吗?(变量v肯定可以看到,根据可见性可以推断出来) 好吧,在旧的JMM模型下,答案是不一定。原因就是CPU指令在执行时的重排序。在旧的JMM模型下,只规定了volatile变量和volatile变量之间不能进行重排序,但是并没有保证volatile变量和non-volatile变量之间不能进行重排序,所以, 当在thread A中,指令的执行可能是:
v = true;
x = 42;
这样,当thread B 看到v为true的时候,x实际上还没有执行,所以值不是42.
慢!眼尖的同学可能看出来了, 你说的这个跟重排序实际上没有关系呀,这个应该算是变量x的可见性问题,因为变量x不是声明为volatile的。
好吧,我承认我偷懒了,在描述volatile变量可见性特质的时候,在新的JMM模型下,当对volatile变量进行写的时候,该线程(这里是thread A)所能看到变量(比如说变量x),都会一起刷新到主存中。这个也就是为什么我们会说对volatile变量的写操作,实际上等价于使用了synchronized关键字后释放monitor时产生的效果。 在这个前提下,上面的问题的确是CPU指令重排序的问题。
但是幸运的是,JMM随后提出了happen-before原则来fix了这个问题(主要是volitale变量和non-volatile变量之间的重排序问题。)
这里我只挑跟这个问题相关的三条原则来进行讲解,其余的可以到官方文档去查看。
1. 单线程原则, 在单线程执行的环境下,指令的执行是跟程序代码的执行顺序一致。 对于上面的例子来说,在程序代码顺序上,x=42 先于 v=true, 那么在内存指令执行的时候也是如此。
2. volatile变量原则,对volatile变量的写操作要优先于对volatile变量的读操作。
3. 转递性原则,如果A操作先于B操作,B操作先于C操作,那么A操作肯定先于C操作。
还是上面的例子,先用单线程原则,可以判断出,在thread A的执行中, x=42肯定要优先于v=true进行执行, 而在thread B的执行中,对v的读取操作肯定要优先于对x的使用操作。
接着再使用volatile变量原则,可以判断,对v的写肯定要先于对v的读, 最后再根据转递性原则, 可以推出在thread A中x=42的赋值操作肯定要先于thread B中对x的使用, 也就是说,当v读取出来是为true的时候,x肯定是42. 指令不会进行重排序。
那如果我们将x=42,v=true的语句倒过来呢?
class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
//颠倒赋值给x,v的顺序。
v = true;
x = 42;
}
public void reader() {
if (v == true) {
//uses x - can we see x is 42 here?
}
}
}
我想通过上面的分析,各位同学自己应该也能推断出来了吧。:)
分享到:
相关推荐
详细说明 并举例说明了VOlatile的作用及用法,特别是嵌入式程序员要注意的
java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java ...
主要介绍了java多线程volatile内存语义解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
c语言下关键字的volatile用法,包含一些基本例子
C语言中关键字volatile的作用,使用说明和例子
const和volatile分析 这个分析得很好 面试 找工作 必备的
一般对于volatile的解释是这样的:将变量定义为volatile可以防止编译器对变量进行优化,每次均从内存中访问变量,而不是寄存器。既然让编译器优化可以提高访问速度,那为什么又要不用它以及什么时候不用它?其实主要...
volatile的用法讲解,讲得很详细,希望能帮助到大家
一般说来,volatile用在如下的几个地方: 1、中断服务程序中修改的供其它程序检测的变量需要加volatile; 2、多任务环境下各任务间共享的标志应该加volatile; 3、存储器映射的硬件寄存器通常也要加volatile说明,...
主要讲述java线程volatile关键字
volatile的用法,在写代码正确使用volatile,正确理解volatile的用法,增强代码的健壮性
容易忽略的变量声明,但是很重要 volatile的作用: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.
C程序中volatile关键字的使用.方法及其例程介绍。
volatile与synchronized的区别,锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)
讲述了volatile_unsigned_int地址映射的使用说明。
前言Java中volatile这个热门的关键字,在面试中经常会被提及,在各种技术交流群中也经常被讨论,但似乎讨论不出一个完美的结果,带着种种疑惑,准备从JVM、
static,const,volatile用法的解析,对三项中全局变量和局部变量的区分,volatile中介绍了其具体用法 和一些区别,bong有例子
深入探讨Java多线程中的volatile变量共6页.pdf.zip
本文给大家介绍了单片机C语言中volatile的作用。
const,extern,static,volatile的使用