Java中volatile关键字的做用

volatile是Java中用来作同步的一个关键字,以前对它的做用一直理解得不是很透彻。html

因而在网上查阅了一些资料,发现也讲得含混不清。java

后来在wikipedia(http://en.wikipedia.org/wiki/Volatile_variable#In_Java)上看到了比较完善的解释。总的来讲,volatile关键字是用来防止编译器作特定优化的,但具体做用取决于使用的语言(如C, C++, C#, Java)。多线程

在Java中,volatile的做用有两点:函数

  1. 对volatile变量的修改可以马上被其余线程知道,也就是说,在读取volatile变量的值时,不是从线程本地的cache读取,而是从主内存读取。这样就能保证多线程对同一个变量的读和写有一个全局的顺序。测试

  2. 能够防止编译器作额外的优化(如调整对变量的读写语句的执行顺序,对while循环的优化等)。优化

网上的资料常常会给出相似这样一个例子:spa

public class Thread1 extends Thread
{
     private static boolean flag = false;
     public void run(){
          while(!flag)
          { 
               // ...
           }
     }
     public void close(){
          flag = true;
     }
}

网上的说法是:线程A在执行run()方法中的while循环,这时线程B调用了close()方法,结果线程A停不下来。由于编译器观察到while循环中没有改变flag的值,就将while(!flag)优化成了while(true)。线程

开始我对编译器是否会优化到这种程度表示怀疑。由于据我实际测试,不管对flag是否加volatile关键字修饰,都是能够停下来的。据个人推测(根据上述volatile的做用第一点),线程A虽然不能在第一时间知道flag值的改变,可是最终仍是会读到正确的值,从而中止while循环。code

后来我去掉volatile关键字,再将while循环的执行次数变长(例如达到1000000000次),这时再调用close()方法,线程A不会停下来了。因此可能HotSpot在while循环执行的次数足够多时才会作while(true)的优化。htm

对于volatile的第二点做用,还有这样一个例子能够用来解释(来自http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile):

public class VolatileExample {
     int x = 0;
     volatile boolean v = false;
     public void writer() {
       x = 42;
       v = true;
     }

     public void reader() {
       if (v == true) {
         //uses x - guaranteed to see 42.
       }
     }
}

在注释处,咱们但愿看到的是x的值等于42。可是若是不加volatile修饰变量v,那么编译器有可能会调整writer()函数中两条语句的执行顺序,致使在注释处x的值不肯定(也多是0)。加上volatile后,即可以防止编译器为了优化随意调整语句的执行顺序。

与普通加锁方式的区别是:加锁机制既能够确保可见性又能够确保原子性,而volatile变量只能确保可见性。

相关文章
相关标签/搜索