`

volatile和重排序得一些小疑问

    博客分类:
  • java
 
阅读更多

http://yeziwang.iteye.com/blog/1042492 

好吧,这里我只想说说volatile在JMM中的语义。

 

  当我们在使用volatile的时候,实际上它表达了下面那么些意思。

 

   1. 可见性。

      这个是大多数人都知道的一个特质, JAVA的线程有自己的工作内存区,与主存区不同,当我们对变量使用了volatile后,那么不管对这个变量的读或写,都会在主存中进行,而不会在处理器的缓存或者寄存器中进行。这个很好理解。

 

 

   2. 禁止CPU指令的重排序

      这个特质的理解稍微要花点脑细胞, 首先我们需要一点premilinary, 当我们的程序编写好了以后,会被翻译成指令集并被加载到内存中去运行。但是,在CPU真正执行的时候,处于性能方面的考虑,这些指令的执行不一定会按照程序中的顺序进行,只要保证其程序执行语义没有变化即可。

 

     来看下代码,

Java代码  收藏代码
  1. class VolatileExample {  
  2.   int x = 0;  
  3.   volatile boolean v = false;  
  4.   
  5.   //in thread A  
  6.   public void writer() {  
  7.     x = 42;  
  8.     v = true;  
  9.   }  
  10.   
  11.   //in thread B  
  12.   public void reader() {  
  13.     if (v == true) {  
  14.       //uses x - can we see x is 42?  
  15.     }  
  16.   }  
  17. }  

 

    在这种情况下,当thread A 执行完后,在thread B中能看到x等于42吗?(变量v肯定可以看到,根据可见性可以推断出来) 好吧,在旧的JMM模型下,答案是不一定。原因就是CPU指令在执行时的重排序。在旧的JMM模型下,只规定了volatile变量和volatile变量之间不能进行重排序,但是并没有保证volatile变量和non-volatile变量之间不能进行重排序,所以, 当在thread A中,指令的执行可能是:

 

Java代码  收藏代码
  1. v = true;  
  2. 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的语句倒过来呢?

 

Java代码  收藏代码
  1. class VolatileExample {  
  2.   int x = 0;  
  3.   volatile boolean v = false;  
  4.   public void writer() {  
  5.     //颠倒赋值给x,v的顺序。  
  6.     v = true;  
  7.     x = 42;  
  8.   }  
  9.   
  10.   public void reader() {  
  11.     if (v == true) {  
  12.       //uses x - can we see x is 42 here?  
  13.     }  
  14.   }  
  15. }  

 

我想通过上面的分析,各位同学自己应该也能推断出来了吧。:)

 

分享到:
评论

相关推荐

    const和volatile分析

    const和volatile分析 这个分析得很好 面试 找工作 必备的

    const extern static volatile 小结

    const extern static volatile 小结

    Volatile详解,深入学习Volatile

    详细说明 并举例说明了VOlatile的作用及用法,特别是嵌入式程序员要注意的

    volatile用法

    c语言下关键字的volatile用法,包含一些基本例子

    volatile的用法讲解

    volatile的用法讲解,讲得很详细,希望能帮助到大家

    C语言中关键字volatile的作用

    C语言中关键字volatile的作用,使用说明和例子

    volatile,nonatomic和atomic关键字测试

    主要研究四种变量(属性)的存取速度. volatile nonatomic atomic和正常变量

    java volatile 关键字实战

    java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java ...

    从汇编角度理解volatile

    一般对于volatile的解释是这样的:将变量定义为volatile可以防止编译器对变量进行优化,每次均从内存中访问变量,而不是寄存器。既然让编译器优化可以提高访问速度,那为什么又要不用它以及什么时候不用它?其实主要...

    volatile与synchronized的区别

    volatile与synchronized的区别,锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)

    Java线程:volatile关键字

    主要讲述java线程volatile关键字

    volatile的使用

    一般说来,volatile用在如下的几个地方: 1、中断服务程序中修改的供其它程序检测的变量需要加volatile; 2、多任务环境下各任务间共享的标志应该加volatile; 3、存储器映射的硬件寄存器通常也要加volatile说明,...

    volatile的用法

    volatile的用法,在写代码正确使用volatile,正确理解volatile的用法,增强代码的健壮性

    static,const,volatile用法

    static,const,volatile用法的解析,对三项中全局变量和局部变量的区分,volatile中介绍了其具体用法 和一些区别,bong有例子

    const和volatile.pdf

    const和volatile

    volatile的使用方法

    C程序中volatile关键字的使用.方法及其例程介绍。

    volatile源码分析1

    前言Java中volatile这个热门的关键字,在面试中经常会被提及,在各种技术交流群中也经常被讨论,但似乎讨论不出一个完美的结果,带着种种疑惑,准备从JVM、

    volatile_unsigned_int

    讲述了volatile_unsigned_int地址映射的使用说明。

    volatile变量详解

    容易忽略的变量声明,但是很重要 volatile的作用: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.

Global site tag (gtag.js) - Google Analytics