众所周知,简单的双重检查有问题,因为JVM使用了命令。
class MyClass {
private String Name;
private static Object o = new Object();
private static MyClass Instance=null;
private MyClass(){
//Thread.sleep(1000);
Name="test case";
}
public static MyClass GetInstance(){
if(Instance==null){
synchronized(o){
if(Instance==null){
Instance = new MyClass();
//MyClass obj = new MyClass();
//Instance = obj;
}
}
}
return Instance;
}
}
如果我将Instance = new MyClass();
替换为注释行。这有用吗?
答案 0 :(得分:1)
不,这不起作用。考虑线程A和B;线程A看到Instance
为null
并输入同步块以生成MyClass
的实例,并将其分配给字段Instance
。
由于Java内存模型的规则,可能会发生重新排序,并且MyClass
的部分初始化或甚至未初始化的对象可以分配给Instance
。现在,线程B进入相同的GetInstance
方法并看到Instance
不为空,从不在与线程A相同的监视器上输入同步块,然后返回未完全初始化的对象。
是否将初始化分成两行代码或将其保留在一行上对此问题绝对没有意义:在任何一种情况下都可能发生重新排序。 Java编译器可以合法地将两个版本的代码编译为相同的字节码(尽管当前的编译器不会)