1. class Foo {
2. private Helper helper = null;
3. public Helper getHelper() {
4. if (helper == null) {
5. synchronized(this) {
6. if (helper == null) {
7. helper = new Helper();
8. }
9. }
10. }
11. return helper;
12. }
13. }
この構造が壊れていると見なされる理由は、一般に、ヘルパー変数への書き込み後にヘルパー コンストラクターが呼び出されるように、コンパイラによって行われる割り当ての並べ替えが説明されています。私の質問は、このコードがどのようにスレッドセーフであり、次の手順が可能かということです。
- スレッド 1、同期ブロックに入り、ヘルパーが null であることを確認します。
- スレッド 1、この時点でモニターをあきらめます
- スレッド 2、オブジェクト モニターに入り、ヘルパーをインスタンス化します。
- スレッド 1 が戻ってきて、ヘルパー インスタンスを次のように再初期化します。
このソリューションが単一のチェック付きロックよりも優れているとは思いません。