0

Javaメモリモデルでは、次のように記述されています。関連するモニターの解放の一部としてスレッドが同期ブロックを終了する場合、JMMはローカルプロセッサキャッシュをメインメモリにフラッシュすることを要求します。同様に、同期ブロックに入るときにモニターを取得する一環として、ローカルキャッシュが無効化されるため、後続の読み取りはローカルキャッシュではなく、メインメモリに直接送信されます。

では、なぜそのコードでインスタンスを揮発性として宣言する必要があるのでしょうか。2番目のスレッドが同期ブロックに入ると、メインメモリに直接移動するからです。

public final class MySingleton {
  private static MySingleton instance = null;
  private MySingleton() { } 
  public static MySingleton getInstance() {
    if (instance == null) {
      synchronized (MySingleton.class) {
        if (instance == null) {
          instance = new MySingleton();
        }
      }
    }
    return instance;
  }
}

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

4

2 に答える 2

4

競合状態は次のとおりです。

  1. スレッドAはinstance == NULLこのコードを確認し、実行していますinstance = new MySingleton();。書き込み先instanceは表示されますが、書き込み先はまだ表示されMySingletonていません。

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

  3. スレッドBは、構造が見えないオブジェクトを処理しています。

JDK5instanceの時点で、JDKメモリ仕様では、揮発性オブジェクトへの書き込みに関して、不揮発性オブジェクトへの書き込みが順不同であると見なされないことが保証されているため、揮発性にすることで問題が解決します。したがって、見るスレッドinstance != NULLはインスタンス自体を見る必要があります。

于 2012-03-13T09:45:21.040 に答える
1

揮発性であると宣言する必要があります。そうしないと、getInstance()を2回呼び出しても同じインスタンスが返される保証はありません。

メインメモリがアクセスされるという保証はなく、キャッシュ整合性のある値のみがアクセスされます。つまり、すべてのスレッドに同じ値が表示されます。

ところで:もちろん、必要以上に複雑なことはご存知でしょう。あなたに必要なのは

public enum MySingleton {
     INSTANCE;
}

ほぼ同じことをします。

于 2012-03-13T09:39:47.670 に答える