http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.htmlの下部には、次のように書かれています。
ダブルチェックされた不変オブジェクトのロック
Helper のすべてのフィールドが final であるなど、Helper が不変オブジェクトである場合、再確認されたロックは揮発性フィールドを使用しなくても機能します。不変オブジェクト (String や Integer など) への参照は、int や float とほぼ同じように動作する必要があるという考え方です。不変オブジェクトへの参照の読み取りと書き込みはアトミックです。
変更可能なもののサンプルと説明は次のとおりです。
// Broken multithreaded version
// "Double-Checked Locking" idiom
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null)
synchronized(this) {
if (helper == null)
helper = new Helper();
}
return helper;
}
// other functions and members...
}
うまくいかない一番の理由
それが機能しない最も明白な理由は、ヘルパー オブジェクトを初期化する書き込みとヘルパー フィールドへの書き込みが実行されたり、順不同で認識されたりする可能性があるためです。したがって、getHelper() を呼び出すスレッドは、ヘルパー オブジェクトへの null 以外の参照を参照できますが、コンストラクターで設定された値ではなく、ヘルパー オブジェクトのフィールドのデフォルト値を参照できます。
コンパイラーがコンストラクターへの呼び出しをインライン化する場合、コンストラクターが例外をスローしたり、同期を実行したりできないことをコンパイラーが証明できれば、オブジェクトを初期化する書き込みとヘルパー フィールドへの書き込みを自由に並べ替えることができます。
コンパイラがこれらの書き込みを並べ替えない場合でも、マルチプロセッサでは、別のプロセッサで実行されているスレッドによって認識されるように、プロセッサまたはメモリ システムがそれらの書き込みを並べ替える場合があります。
私の質問は、なぜ不変クラスに問題がないのですか? クラスが変更可能かどうかとの並べ替えの関係はわかりません。
ありがとう