Java的 volatile易变量成员修饰符
时间:2010-10-10 来源:juxiangwu
volatile关键字用成员变量的一个修饰符,每次线程访问该变量时,强迫它从共享内存中重读变量的值。而且,当变量发生变化时,强迫线程将变化值写回到共享内存。如此一来,在任何特定时刻,两个不同的线程总是看到某个成员变量的同一个值。Java语言表明,为了获得最佳速度,允许线程保存共享成员变量的工作拷贝,而且只是偶而用共享的原始值来校准。为了更准确地描述,上一句中使用的“偶而”一词应该用以下表达代替:“当线程进入或离开同步代码块时”。如果仅有一个线程与对象的成员变量交互时,优化工作就非常理想,可以使执行更快。当两个(或更多)线程同时与某个对象交互时,这时就必须小心,确保一个线程对共享成员的改变能让另一个线程知道。
volatile关键字用于告诉VM:它不应该保存变量的私有拷贝,而应当直接与共享拷贝交互。
在Sun Microsystem JDK 1.2中VM默认命令行选项运行Volatile的输出。如果关闭了内置Just-In-Time(JIT)编译器,使用如下命令:
Java –Djava.compiler=NONE Volatile。
在关闭JIT后,所有线程直接读写共享内存,也不会保存变量的私有拷贝。就像每个成员变量都声明volatile一样。
或JIT才会产生差异。JIT执行优化,使
版本
|
命令行
|
Volatile是否有用
|
JDK 1.2
|
Java Volatile
|
是
|
JDK 1.2
|
Java –Djava.compiler=NONE Volatile
|
否
|
JDK 1.1
|
Java Volatile
|
是
|
JDK 1.1
|
Java –nojit Volatile
|
否
|
JDK 1.0
|
Java Volatile
|
否
|
Sun在VM中包含JIT之前,使用volatile无差异。另外,甚至包含JIT后,每个线程进入或离开同步块,它都会让变量的私有拷贝与共享拷贝一致。Synchronized代码块分布在java.*类库中,因此,开发人员可能没有意识到私有拷贝已经被校准了。例如,Systme.out.println()包含一个synchronized块,所以,在Volatile中使用它打印当前value,保持私有变量为最新值,volatile修饰符似乎没有发挥作用。许多开发人员编写过在一些成员变量上应用了volatile修饰符的代码。但是至少因为以上其中一个原因,volatile不能产生关键性的区别。
Volatile修饰符的存在要求VM总是访问变量的共享拷贝。与VM通过保存一份私有拷贝来执行优化相比,它的效率要低。只在必要时使用volatile,滥用volatile会导致不必要地降低应用程序的执行速度。
小技巧:
在两个或更多线程访问的成员变量上使用volatile时,除非所有的线程都访问synchronized代码块内的变量。如果成员变量构建后保持为常量(即只读),就没有必要声明为volatile。
相关阅读 更多 +