JVM指令重排导致Singleton双重锁定出错

指令重排导致单例模式失效

我们都知道一个经典的懒加载方式的单例模式:

public class Singleton {

private static Singleton instance = null;

private Singleton() { }

public static Singleton getInstance() {

if(instance == null) {

synchronzied(Singleton.class) {

if(instance == null) {

instance = new Singleton();

}

}

}

return instance;

}

}

看似简单的一段赋值语句:instance = new Singleton();,其实JVM内部已经转换为多条指令:

memory = allocate(); //1:分配对象的内存空间

ctorInstance(memory); //2:初始化对象

instance = memory; //3:设置instance指向刚分配的内存地址

但是经过重排序后如下:

memory = allocate(); //1:分配对象的内存空间

instance = memory; //3:设置instance指向刚分配的内存地址,此时对象还没被初始化

ctorInstance(memory); //2:初始化对象

可以看到指令重排之后,instance指向分配好的内存放在了前面,而这段内存的初始化被排在了后面,在线程A初始化完成这段内存之前,线程B虽然进不去同步代码块,但是在同步代码块之前的判断就会发现instance不为空,此时线程B获得instance对象进行使用就可能发生错误。


修改:

public class Singleton {

	private static  volatile Singleton instance = null;

	private Singleton() { }

	public static Singleton getInstance() {

	if(instance == null) {

	synchronzied(Singleton.class) {

		if(instance == null) {

			instance = new Singleton();

			}

		}

	}

		return instance;

	}

}


你可能感兴趣的:(JAVA)