我读到单例的双重检查机制是失败的,因为 JVM 遵循的某些内存模型使得即使构造函数尚未完全执行,引用也不会为空。
我尝试通过在下面的代码中的构造函数内进行耗时操作来测试相同的内容,但即使如此,它似乎也工作正常。
public class Singleton {
private static Singleton singleton;
private Integer i = 0;
private Singleton() {
for(long j = 0; j<99999999; j++){
double k = Math.random();
k= k+1;
}
i = 10;
}
private static Singleton getSinglton() {
if(singleton == null){
synchronized (Singleton.class) {
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
public static void main(String[] args) {
Runnable runnable1 = new Runnable() {
@Override
public void run() {
Singleton singleton = Singleton.getSinglton();
System.out.println(singleton.getI());
}
};
Thread t1 = new Thread(runnable1);
Thread t2 = new Thread(runnable1);
Thread t3 = new Thread(runnable1);
Thread t4 = new Thread(runnable1);
Thread t5 = new Thread(runnable1);
Thread t6 = new Thread(runnable1);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
public void setI(Integer i) {
this.i = i;
}
public Integer getI() {
return i;
}
}
我得到的结果是 10 10 10 10 10 10
我期望很少有线程读取值 0 ,而不是 10 ,但每次该值都被正确读取为 10 ,所以这个问题在 Java SE-1.6 中解决了,因为我使用的是相同的?
最佳答案
首先,不要使用 DSL,不是因为它有问题,而是因为它过于复杂。
enum Singleton {
INSTANCE;
}
这不仅更简单,而且速度更快,因为它不需要 getInstance() 所做的检查。
其次,九年前,DSL 就被固定在 Java 5.0 的内存模型中。
最后,即使模型被破坏,也不能保证它会在特定版本的 Java 中显示。只是不能保证它适用于所有版本的 Java。 Sun 版本的 Java 倾向于修复 JLS 未很好涵盖的问题。
关于java - 对单例的双重检查似乎工作得很好而不会被破坏,为什么以及如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19208813/