java并发系列-Volatile

以下转发自大牛文章: http://flychao88.iteye.com/blog/1521235
Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。
这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。
而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。
由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。 
******************原文结束,学习笔记开始(参见:并发编程的艺术)*************************
体会自己以前头一次看这些技术文章的时候,不是很理解意思。其实是基础不够好,对java内存模型理解不够深入。
java并发系列-Volatile_第1张图片
看看上面这个图,结合之前的文字介绍,就清晰了不少。
先写出volatile特点:
可见性:对于一个 volatile变量的读,总能看到任意线程对这个 volatile变量最后的写入。
原子性:对于任意单个 volatile变量的读写具有原子性,但是类似于 volatile++这种复合操作不具备原子性。
有序性:主要是禁止指令重排序。
适应场景:单个线程写,多个线程读。提供一种比锁更轻量级的通信机制。在功能上锁比 volatile功能更强大,可提供整个临界区代码的执行具有原子性。在执行性能上, volatile更有优势。所以如果想用 volatile替代锁,要注意场景:1)对变量的写操作不依赖于当前值,2)该变量没有包含在具有其他变量的不变式中。其实就是为了保证操作是原子性的。
印象中场景操作是用作Boolean类型的flag上,用作线程优雅停止运行的条件。

看到这里可以理解上面大牛的文章描述了,如果要进一步理解大牛说的使用建议,提高代码效率,可以从JMM看如何实现 volatile内存语义。在执行程序时为了提高性能,编译器跟 处理器经常对指令进行重排序,这些重排序可能会对多线程程序出现内存可见性问题,对于编译器,JMM的编译器重排序规则会禁止编译器对特定类型的编译器重排序,对于处理器,JMM的处理器重排序规则要求java编译器 在生成字节码时,会在指令序列插入内存屏障来禁止特定类型的处理器重排序 (重排序这个有点扯远了,没办法,属于基础)。为了实现 volatile的内存语义,编译器在生成字节码时,会在指令序列插入内存屏障来禁止特定类型的处理器重排序。这种策略非常保守,但是可以保证跨处理器平台正确的得到 volatile内存语义。 这里可以理解为优先保证正确性,再追求效率。
*****************************************
最后还是要多看并发编程网上有关文章,深入了解jvm及JMM,写的很仔细。

你可能感兴趣的:(多线程,并发,volatile)