0

Javaメモリモデルでは、関連するモニタの解放の一環としてスレッドが同期ブロックを終了するときに、JMMはローカルプロセッサキャッシュをメインメモリにフラッシュする必要があります。同様に、同期ブロックに入るときにモニタを獲得する一部として、は、ローカルキャッシュが無効にされるので、後続の読み出しはローカルキャッシュではなくメインメモリに直接行われる。同期の前にメモリを更新しますか?

このコードでは、2番目のスレッドがsynchブロックに入るとメインメモリに直接移動するので、なぜインスタンスをvolatileとして宣言しなければならないのですか?

つまり、別のスレッドが同期ブロックに入り、2番目のチェックを行うと、前述のようにメインメモリから更新されるはずです。

+1

[Java Double Checked Locking](http://stackoverflow.com/q/1625118/651140) –

+0

[この「Double-Checked Lockingが壊れています」という宣言]を読まずにこのコードにどのように到達しますか? http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)?すべてが簡単に理解できる用語で説明されています。 – Ringding

+0

より多くの説明をしてください...私は、同期ブロックのローカルキャッシュに入るときのスレッドは無効になるので、後続の読み込みはメインメモリに直接行くので、スレッドBは揮発性でなくてもメインメモリからそのインスタンス値を更新するはずです。 – Dorgham

答えて

4

競合状態はこれです:

  1. スレッドAはinstance == NULLを見て、このコードinstance = new MySingleton();を実行しています。 instanceへの書き込みは見えますが、MySingletonへの書き込みはまだありません。

  2. スレッドBはinstance != NULLを表示し、インスタンスで作業を開始します。

  3. スレッドBは、構造が見えないオブジェクトで作業しています。 instanceが揮発作る

はJDK5のように、非揮発性のオブジェクトへの書き込み保証がvolatileオブジェクトへの書き込みに関して順不同で表示されません、JDKメモリの仕様として、問題を解決します。したがって、instance != NULLを参照するスレッドはインスタンス自体を参照する必要があります。

+1

具体的には、MySingletonのコンストラクタによって行われた書き込みは、スレッドBが見ることが保証されていません。 – Ringding

+0

しかし、スレッドAが同期のロックを解除していない間にスレッドBはインスタンスを見ることができます(スレッドAはキャッシュをフラッシュしませんでしたスレッドBはinstance = nullの古い値を参照する必要があります。 – Dorgham

+1

書き込みがキャッシュにロックされていません。キャッシュは常にフラッシングしているか、フルになり、CPUからの書き込みがストールします。キャッシュをフラッシュすると、フラッシュされたことが保証されます。それを洗い流してもそれには何も付いていません。 –

1

これを宣言しなければ、getInstance()を2回呼び出すと同じインスタンスが返されるという保証はありません。

メインメモリにアクセスする保証はなく、キャッシュ一貫性のある値のみです。全てのスレッドは同じ値を見る。

ところで、あなたはもちろん、必要以上に複雑です。必要なのは

public enum MySingleton { 
    INSTANCE; 
} 

とほとんど同じことです。

関連する問題