public class Singleton1 {
private static volatile Singleton1 instance;
private Singleton1() {
}
public static Singleton1 getInstance() {
// 第一次检测
if (null == instance) {
// 同步
synchronized (Singleton1.class) {
if (null == instance) {
// 多线程环境可能出问题的地方
instance = new Singleton1();
}
}
}
return Singleton1.instance;
}
}
因为volatile会禁用相关重排序,所以instance实例化步骤如下
- memory=allocate() //1.分配对象内存空间
- instance(memory) //2.初始化对象
- instance=memory //3.设置instance指向刚分配的内存地址,此时 instance != null
如果不加volatile修饰,在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性
- memory=allocate() //1.分配对象内存空间
- instance=memory //3.设置instance指向刚分配的内存地址,此时 instance != null
- instance(memory) //2.初始化对象
多线程环境会出现上面这种情况,导致虽然instance != null,但是对象没有被真正的初始化
volatile变量为何立即可见
- 当写一个volatile变量时,JMM会把该线程对应的工作内存中的共享变量值刷新到主内存中
- 当读取一个volatile变量时,JMM会把该线程对应的工作内存置为无效