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..."); } }