volatile
特性:
- 可见性:多线程下,一个线程对变量的修改,能立即被其他线程看到.
- 禁止指令重排序:编译器和CPU在变量前后的指令不能被乱序执行,本质是JMM会加入内存屏障保证,顺序不会乱序。
volatile在Java里面的运算操作符并非原子操作,这导致volatile变量的运算在并发下一样是不安全的.
案例:下面的案例中,虽然race是volatile修饰的,但是volatile并不是原子操作。
public class VolatileTest {
private static volatile int race = 0;
public void increase() {
race++;
}
public int getRace() {
return race;
}
public static void main(String[] args) throws InterruptedException {
VolatileTest volatileTest = new VolatileTest();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
volatileTest.increase();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
volatileTest.increase();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(volatileTest.getRace());
}
}
对于指令重排序的案例:
public class Singleton {
private static Singleton instance;
public Singleton getInstance(){
if(Objects.isNull(instance)){ // 多线程可能同时进入
instance = new Singleton();
}
return instance;
}
public static void main(String[] args) {
Singleton singleton = new Singleton();
new Thread(()->{
Singleton instance = singleton.getInstance();
System.out.println(instance.toString());
}).start();
new Thread(()->{
Singleton instance = singleton.getInstance();
System.out.println(instance.toString());
}).start();
new Thread(()->{
Singleton instance = singleton.getInstance();
System.out.println(instance.toString());
}).start();
}
}
instance = new Singleton();
- 分配内存给对象
- 初始化对象(执行构造函数)
- 把对象地址赋值给 instance
在没有 volatile 的情况下,CPU 可能发生指令重排序 - 分配内存
- 把地址赋给 instance(此时 instance != null)
- 初始化对象
问题:如果线程 A 执行到第 2 步(还没初始化完),线程 B 看到 instance != null 就拿去用了,就出错了!
下图中,左边红色框中这行,用字节码翻译过来时右边红框这4行,而蓝色框这两行就是初始化过程中会发生指令重排序,当线程A执行INVOKESPECIAL时,线程B来判断instance!=null,会获取一个半初始化的instance实例。所以Singleton必须加volatile。
"半初始化对象"指的是对象已经被分配内存,但是还没有完成构造函数的初始化。这种情况下,其他线程读取到的对象虽然不为 null,但其内部状态是未定义的,可能导致程序行为异常甚至崩溃。
![image]()
正确的做法:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {} // 私有构造器
public static Singleton getInstance() {
if (instance == null) { // 外层非同步,提高性能
synchronized (Singleton.class) {
if (instance == null) { // 内层同步,线程安全
instance = new Singleton();
}
}
}
return instance;
}
}


浙公网安备 33010602011771号