初めに:
この場合も、synchronized キーワードを使用すると、JMM 仕様に従ってコードの並べ替えが発生することはありません。
上記の記述は完全に正確ではありません。JMM は、事前発生の関係を定義しました。JLS は、プログラムの順序と先行発生順序のみを定義します。17.4.5を参照してください。ご注文前に発生します。
命令の並べ替えに影響します。例えば、
int x = 1;
synch(obj) {
y = 2;
}
int z = 3;
上記のコードでは、以下のタイプの並べ替えが可能です。
synch(obj) {
int x = 1;
y = 2;
int z = 3;
}
上記は有効な並べ替えです。
Roach Motels と Java メモリ モデルを参照してください。
synch(obj) {
int z = 3;
y = 2;
int x = 1;
}
上記も有効な並べ替えです。
不可能なことは、ロックが取得された後、ロックが解放される前にのみ y=2 が実行されるということです。これは、JMM によって保証されています。また、別のスレッドからの正しい効果を確認するには、同期ブロック内でのみ y にアクセスする必要があります。
今、私はDCLに来ています。
DCL のコードを参照してください。
if (singleton == null)
synch(obj) {
if(singleton == null) {
singleton == new Singleton()
}
}
return singleton;
上記のアプローチの問題は次のとおりです。
singleton = new Singleton()
単一の命令ではありません。しかし、一連の指示。コンストラクターを完全に初期化する前に、最初にシングルトン参照にオブジェクト参照が割り当てられる可能性は十分にあります。
したがって、1が発生した場合、他のスレッドがシングルトン参照を非 null として読み取り、部分的に構築されたオブジェクトを参照している可能性が十分にあります。
上記の効果は、シングルトンを volatile にすることで制御できます。これにより、事前発生の保証と可視性も確立されます。