3
class MyClass
{
  private static volatile Resource resource;

  public static Resource getInstance()
  {
            if(resource == null)
                      resource = new Resource();
            return resource;
  }
}

ここで、Resourceが不変のクラスである場合、上記のコードを記述しても安全ですか?実際のJava同時実行の場合と同様に、「初期化の安全性により、適切に構築された不変オブジェクトをスレッド間で安全に共有できます。したがって、上記のコードは安全に記述できます」と述べられています。(ページ番号349 16.3)。しかし、これを使用すると、2つのスレッドがnullをチェックし、クラスの不変条件(シングルトン)に反するオブジェクトの作成に進むことができる場合があります。説明してください。リンクの質問の続き

4

1 に答える 1

6

いいえ、これはスレッドセーフなコードではありません。この場合、Resourceスレッドセーフである可能性がありますが、getInstanceメソッドはそうではありません。

この一連の流れを想像してください

Thread1 calls getInstance and checks "if resource == null" and then stops (because the OS said it was time for it to be done) before initializing the resources.

Thread2 calls getInstance and checks "if resource == null" and then initializes the instance

Now Thread1 starts again and it also initializes the instance.

現在は 2 回初期化されており、シングルトンではありません。

スレッドセーフにするためのオプションがいくつかあります。

  1. メソッドをgetInstance同期させる

  2. 宣言時に (または静的初期化子で) インスタンスを初期化し、getInstanceそれを返すことができます。

また、変数を揮発性にする必要もありません。ケース #1 では、メソッドを同期すると変数がフラッシュされるため、すべての変数に更新されたコピーが表示されます。ケース #2 では、オブジェクトは構築後にすべてのオブジェクトから見えることが保証されます。

于 2013-02-26T00:32:16.990 に答える