以下のコード スニペットは、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;
}
したがって、初期化が完了した後は、揮発性の読み取りまたは同期のオーバーヘッドのためにスレッドを実行する必要はありません。私の仮定が正しいかどうかを確認してください。