众所周知,简单的双重检查由于 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();
替换为注释行。这有效吗?
最佳答案
不,这不起作用。考虑线程A和B;线程 A 看到 Instance
为 null
并进入同步块(synchronized block)创建 MyClass
的实例并将其分配给字段 Instance
.
由于Java内存模型的规则,可能会发生重新排序,并且MyClass
的部分初始化甚至未初始化的对象可以被分配给Instance
。现在,线程 B 进入相同的 GetInstance
方法,并发现 Instance
不为 null,永远不会在与线程 A 相同的监视器上进入同步块(synchronized block),然后返回一个对象,该对象为未完全初始化。
是否将初始化拆分为两行代码或将其保留在一行上对于此问题绝对没有意义:在任何一种情况下都可能发生重新排序。 Java 编译器可以合法地将代码的两个版本编译为相同的字节码(尽管当前的编译器不会)
关于java单例与双重检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36490101/