前置知识点,Java 中一条语句可能被解析成多条指令分别执行(不一定保证原子性)
如下语句:
User user = new User();
会被解析成多步操作执行
- 在堆内存中为新的
User
对象分配空间。 - 在栈内存中为变量
user
分配空间。 - 调用
User
类的构造函数来初始化这个新对象。 - 将新创建的
User
对象在堆内存中的地址赋值给栈内存中的变量user
。
正常情况下,应该会按照顺序执行,但是由于编译器有优化执行顺序的功能(提升cpu执行的效率),所以不一定是按照此顺序执行;
但是优化一定会保证 单线程
情况下,执行结果的正确性.
比如优化的结果可能是,1243 ,在单线程情况下不会出现问题.
如果双重校验锁(DCL) 不加 volatile (内存屏障)会出现什么问题
public class SingleInstance {
private static SingleInstance instance;
// private static volatile SingleInstance instance;
private SingleInstance() {
}
public static SingleInstance getInstance() {
if (instance == null) {
synchronized (SingleInstance.class) {
if (instance == null) {
instance = new SingleInstance();
}
}
}
return instance;
}
}
可能出现的情况:
线程A: 执行顺序为 1243,但是执行到了第4步就发生了线程切换,此时对象还没有初始化
线程B:切换到B线程时,才到 instance == null
这一步,由于 线程A 已经执行了变量赋值操作,所以 instance == null
为 false,便 retrun 了一个 未初始化的 instance;