Java中volatile关键字的作用

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

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

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

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

在Java中,volatile的作用有两点:

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

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

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

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循环。

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

对于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变量只能确保可见性。

转载于:https://my.oschina.net/roll1987/blog/206372

你可能感兴趣的:(Java中volatile关键字的作用)