Volatile的英文意思是 易挥发的/易变的,一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么它就具备了两层语义:
-
保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(与JVM内存模型有关,注意区分和Static的区别)
-
禁止进行指令重排序。
1.可见性:
//线程1
boolean flag = false;
while(!flag){
doSomething();
}
//线程2
flag = true;
这段代码不一定会将线程中断,也许在大多数时候,这个代码能够把线程中断,但是也有可能会导致无法中断线程(虽然这个可能性很小,但是只要一旦发生这种情况就会造成死循环了)。为了防止这类问题(退出线程常用到volatile),用volatile修饰flag来保证其可见性。
2.禁止JVM进行指令重排序:
/线程1:
context = loadContext(); //语句1
inited = true; //语句2
//线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);
由于JVM的重排序,可能语句2会在语句1之前执行,那么久可能导致context还没被初始化,而线程2中就使用未初始化的context去进行操作,导致程序出错。
这里如果用volatile关键字对inited变量进行修饰,就不会出现这种问题了,因为当执行到语句2时,必定能保证context已经初始化完毕。
场景:单例(双重检测)
class Singleton{
private volatile static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if(instance==null) {
synchronized (Singleton.class) {
if(instance==null)
instance = new Singleton();
}
}
return instance;
}
}