两个作用:
- 在当前的java内存模型下,线程可以把变量保存在本地内存中,比如说机器的寄存器,而不单单是在主内存中进行读写,所以有可能出现这样的情况:一个线程在主存中更改了一个变量的值,另外一个线程在本地内存中读取了这个变量值的旧值,这就造成的数据的不一致。而将变量声明为volatile则是告诉jvm这个变量是不稳定的没每次都要从主存中读取。
- 可以防止指令的重排。
看个例子:多线程下单例模式的线程安全
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
//先判断对象是否已经实例过,没有实例化过才进入加锁代码
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
代码中,uniqueInstance = new Singleton();分为三步执行:
- 在堆中为uniqueInstance 分配内存空间;
- 执行new Singleton()的初始化操作;
- 将uniqueInstance 指向对应的内存空间;
但是,jvm有指令重排的特性,即执行顺序可能变为1->3->2。假设线程1执行了1和3;此时线程2进入方法,发现uniqueInstance 不等于null,直接返回uniqueInstance,但uniqueInstance还没有初始化,就会出现线程安全的问题。使用volatile禁止指令重排便能解决此问题。