Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量(不稳定变量)。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。举例说明:
**
volatile int v;
void func()
{ int a,b;
a=5*v;
b=5*v;
....
}
如果v是个普通的变量,编译器很可能会做这样的优化,第一次计算出5*v的值后,先赋给a,然后直接又从寄存赋给b,而不会重新计算5*v.
但如果定义成volatile,编译器则不会做任何优化,每次都会
重新读取v的值.这样一来,即便在执行a=5*v之后,有可能恰好在此时出现中断,将v的值改变,这时再执行b=5*v,结果应该是a和b的值不相同,但如果编译器按上面的规则一优化,则a和b永远会相同,为了避免出现这种情况,于是将v定义成volatile的.
**
Volatile 变量具有 synchronized 的可见性特性(也就是上例所说的对编译器的可见性),但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例 。
适用条件
只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
**
- 对变量的写操作不依赖于当前值。
- 该变量没有包含在具有其他变量的不变式中。
实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。这两个条件看起来很晕,但只要暂时理解为,他虽然起到了一定的安全作用,但无法满足原子性。
第一个条件的限制使 volatile 变量不能用作线程安全计数器。虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变,而 volatile 变量无法实现这点。(然而,如果将值调整为只从单个线程写入,那么可以忽略第一个条件。)
大多数编程情形都会与这两个条件的其中之一冲突,使得 volatile 变量不能像 synchronized 那样普遍适用于实现线程安全。
更加深入的学习见http://www.ibm.com/developerworks/cn/java/j-jtp06197.html**