5

以下のコード スニペットは、Effective Java 2nd Edition Double Checked Locking からのものです。

// インスタンス フィールドの遅延初期化のイディオムを再確認します

private volatile FieldType field;

FieldType getField() {
    FieldType result = field;
    if (result == null) {  // First check (no locking)
        synchronized(this) {
            result = field;
            if (result == null)// Second check (with locking)  
                field = result = computeFieldValue();
        }
    }
    return result;
}

私が知っていることから、ダブルチェックロックの主な問題は、2番目のチェックロック内での並べ替えであり、他のスレッドがフィールド/結果の値を設定されたものとして認識し、実際にはまだ実行中の可能性があります。これを回避するために、フィールドの参照を揮発性として作成し、可視性と並べ替えを保証します。

ただし、これは以下のコードでも実現できます

private FieldType field; // non volatile
private volatile boolean fence = false;

FieldType getField() {
    if (field == null) {  // First check (no locking) // no volatile read
        synchronized(this) {   //  inside synch block no problem of visibilty will latest           //value  of field 
            if (field == null) {// Second check (with locking)  
                Object obj =  computeFieldValue();
             fence = true; // any volatile write will take. this will make sure statements are //not reorder with setting field as non null.
            field = (FieldType)obj; // this will be only set after computeFieldValue has been //completed fully
           }
        }
    }
    return field;
}

したがって、初期化が完了した後は、揮発性の読み取りまたは同期のオーバーヘッドのためにスレッドを実行する必要はありません。私の仮定が正しいかどうかを確認してください。

4

3 に答える 3

9

JLS (セクション 17.4.5)は次のように述べています。

「揮発性フィールド(§8.3.1.4)への書き込みは、そのフィールドの後続のすべての読み取りの前に発生します。」

変数が更新された後に変数を読み取っていないfenceため、更新するスレッドfenceと 2 番目のスレッドとの間に「発生前」の関係はありません。つまりfield、最初のスレッドによって行われた変数への更新を 2 番目のスレッドが確認できる保証はありません。

要するに、「改善された」コードは、ダブルチェック ロックの壊れた実装です。

于 2013-06-18T13:02:56.913 に答える