コンストラクターが完全に実行されていなくても、参照が null ではない読み取りを行う 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 です
10 ではなく値 0 を読み取るスレッドはほとんどないと予想していましたが、値が 10 として正しく読み取られるたびに、Java SE-1.6 で同じものを使用しているため、問題は解決しましたか?