这篇文档居然在我的优盘里躺了很久,知道整理U盘文件的时候才发现居然还没有粘到blog上。
多cpu就意味着多个寄存器,实践证明,拥有一个多核cpu对于一个coder来说还是很重要的。
Declaring a volatile Java variable means:
· The value of this variable will never be cached thread-locally: all reads and writes will go straight to "main memory";
· Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself.
Difference between synchronized and volatile
Characteristic | Synchronized | Volatile |
Type of variable | Object | Object or primitive |
Null allowed? | No | Yes |
Can block? | Yes | No |
All cached variables synchronized on access? | Yes | From Java 5 onwards |
When synchronization happens | When you explicitly enter/exit a synchronized block | Whenever a volatile variable is accessed. |
Can be used to combined several operations into an atomic operation? | Yes | Pre-Java 5, no. Atomic get-set of volatiles possible in Java 5. |
In other words, the main differences between synchronized and volatile are:
· a primitive variable may be declared volatile (whereas you can't synchronize on a primitive with synchronized);
· an access to a volatile variable never has the potential to block: we're only ever doing a simple read or write, so unlike a synchronized block we will never hold on to any lock;
· because accessing a volatile variable never holds a lock, it is not suitable for cases where we want to read-update-write as an atomic operation (unless we're prepared to "miss an update");
· a volatile variable that is an object reference may be null (because you're effectively synchronizing on the reference, not the actual object).
· Attempting to synchronize on a null object will throw a NullPointerException.(以前没有注意过这个问题)
我们知道,在Java中设置变量值的操作,除了long和double类型的变量外都是原子操作,也就是说,对于变量值的简单读写操作没有必要进行同步。
这在JVM 1.2之前,Java的内存模型实现总是从主存读取变量,是不需要进行特别的注意的。而随着JVM的成熟和优化,现在在多线程环境下volatile关键字的使用变得非常重要。
在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。
要解决这个问题,只需要像在本程序中的这样,把该变量声明为volatile(不稳定的)即可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。
Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。
这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。
由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。
注:我在单例模式中用到此关键字.
http://qingfeng825.javaeye.com/blog/152269 转自一个美女的blog
http://www.javamex.com/tutorials/synchronization_volatile.shtml
http://www.javamex.com/tutorials/synchronization_volatile_typical_use.shtml
http://www.javamex.com/tutorials/synchronization_concurrency_synchronized2.shtml