代码改变世界

volatile

2012-09-20 20:24  康杜  阅读(1260)  评论(1编辑  收藏  举报

volatile是什么

对于volatile, <The Java Language Specification Third Edition>是这样描述的

“A field may be declared volatile, in which case the Java memory model ensures that all threads see a consistent value for the variable.”
意思是,如果一个变量声明为volatile, Java 内存模型保证所有的线程看到这个变量的值是一致的。
 
“… the volatile modifier guarantees that any thread that reads a field will see the most recently written value.” - Josh Bloch
Josh Bloch 说 ”volatile描述符保证任意一个程序读取的是最新写的值“
 
有人会问,内存不是存放变量值的地方吗,线程T1写,然后线程T2读,怎么会出现不一致的情况呢。

缓存

实际上内存不是唯一存储变量的地方。CPU往往会把变量的值存放到缓存中。假如一个CPU,即使在多线程环境下也不会出现值不一致的情况。但是,在多CPU,或者多核CPU的情况就不是这样了。如下图所示,在多个CPU情况下,每个CPU都有独立的缓存,CPU通过连接相互获取缓存内容。线程T1的可能运行在CPU 0上,它从内存中读取值放到缓存中做运算,比如执行方法foo;线程T2运行于CPU 1上,执行方法bar。
 void foo(void)
 {
   a = 1;
   b = 1;
  }

 void bar(void)
 {
  while (b == 0) continue;
  assert(a == 1);
 }

 在多CPU情况下,由于CPU各自缓存的原因,线程可能观察到不一致的变量值。

按我的理解,volitate标志通过CPU基本的指令,比如(mfence x86 Xeon 或 membar SPARC)添加内存界限,让缓存和内存之间的值进行同步。 

 

参考资料:

Memory Barrierhttp://en.wikipedia.org/wiki/Memory_barrier 

为什么需要Memory Barrier http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.06.07c.pdf

Java 内存模型和Memory Barrier www.infoq.com/articles/memory_barriers_jvm_concurrency

volatile的一个作用

由于volatile保证一些线程写的值,另外一些线程能够立即看得到。我们可以通过这一特性,实现信号或事件机制。比如下面程序里主线程可以发送信号(把stopSignal设为true), 把线程workerThread立即终止。

 

public class  WorkerOwnerThread

{

    // field is accessed by multiple threads.

    private static  volatile boolean  stopSignal;



    private static  void  doWork()

    {

        while (!stopSignal)

        {

        Thread t = Thread.currentThread();  

        System.out.println(t.getName()+ ": I will work until i get STOP signal from my Owner...");

        }

    System.out.println("I got Stop signal . I stop my work");

    }



    private static   void stopWork()

    {

    stopSignal = true;

    //Thread t = Thread.currentThread();  

    //System.out.println("Stop signal from " + t.getName()  ); 

    }

  

  

    public static void main(String[] args) throws InterruptedException {



    Thread workerThread = new Thread(new Runnable() {

        public void run() {

            doWork();    } 

        });

    workerThread.setName("Worker");

    workerThread.start();



    //Main thread

    Thread.sleep(100);

    stopWork();

    System.out.println("Stop from main...");

    }

}