これが私のシングルトンクラスです。
staticinstanceフィールドは揮発性ではないため、並べ替え/可視性の問題が発生します。それを解決するために、インスタンスvalフィールドは final になります。インスタンスは適切に構築されているため、インスタンスが表示される場合、クライアントは常にvalフィールドが初期化されていることを確認する必要があります。
static class Singleton {
private static Singleton instance;
private final String val;
public Singleton() { this.val = "foo"; }
public static Singleton getInstance() {
if (instance == null)
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
return instance;
}
public String toString() { return "Singleton: " + val; }
}
ただし、別の問題があります-「インスタンス」フィールドの保護されていない読み取りが2つあり、クライアントが実際の値ではなくnullを取得できるように並べ替える(?)ことができます:
public static Singleton getInstance() {
Singleton temp = instance;
if (instance != null) return temp;
else { /* init singleton and return instance*/ }
}
これを回避するには、ローカル変数を導入できるように感じます。
public static Singleton getInstance() {
Singleton temp = instance;
if (temp == null)
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
temp = instance;
}
}
return temp;
}
保護されていない値の読み取りは 1 つしかないため、これで問題が解決したように見えます。しかし...シングルスレッドのセマンティクスを変更せずに(ほとんど?)プログラムフローを変更しました。これは、この変換は安全であり、volatile との適切な事前発生関係を確立せずにこのコードを機能させる方法がないため、コンパイラが私の回避策を元に戻すことができるということですか?