3

Java Concurrency In Practice で、著者は次のように述べています。

  1. 不変オブジェクトは、任意のメカニズムを介して公開できます
  2. 不変オブジェクトは、同期を使用して公開していない場合でも、追加の同期なしで任意のスレッドで安全に使用できます。

次のイディオムは、不変オブジェクトを安全に公開できるということですか?

public static List<ImmutableObject> list = new ArrayList<ImmutableObject>();

// thread A invokes this method first
public static void methodA () {
    list.add(new ImmutableObject());
}

// thread B invokes this method later
public static ImmutableObject methodB () {
    return list.get(0);
}

データ競合はありますか?(つまり、スレッド B は、スレッド A によって追加されたリスト内の不変オブジェクトを認識できない可能性があります)

どうもありがとうございました。


さらに、著者は、リソースが不変である場合、次のコードは安全であると述べました。

@NotThreadSafe
public class UnsafeLazyInitialization {
    private static Resource resource;

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

セクション16.3 初期化の安全性の保証により、適切に構築された不変オブジェクトは、データ競合を使用して公開された場合でも、公開方法に関係なく、同期せずにスレッド間で安全に共有できます。(これは、が不変でunsafeLazyInitializationあれば実際には安全であることを意味します。)Resource

この質問の 2 番目の部分については、別の質問 (ここをクリック) で詳しく説明されています

4

4 に答える 4

5

はい、その通りです。データ競合があります。

のみImmutableObjectが不変であり、スレッド間で安全に共有できますが、あなたのListにはこれらと同じ保証がないため、 の追加ImmutableObjectと取得の間にデータ競合が発生します。

JCIP では、作成者は、防御コピーの作成などを行うことについて心配する必要がないという意味で、不変オブジェクトを公開しても安全であると述べました。

に関して:

不変オブジェクトは、同期を使用して公開していない場合でも、追加の同期なしで任意のスレッドで安全に使用できます。

このステートメントは、2 つのスレッドがA何らかの手段で取得した不変オブジェクトを持つ場合、Aスレッド セーフの問題を気にせずにオブジェクトを使用できることを意味します。

于 2013-01-31T02:39:57.707 に答える
3

List<ImmutableObject> listコンテナ オブジェクトは不変ではありません。したがって、 add および get メソッドはスレッドセーフではありません。これらのメソッドは、複数のスレッドからの同時アクセスのために同期する必要があります。

于 2013-01-31T02:43:50.063 に答える
1

あなたの質問は、セクション5.3-キューのブロックと生産者/消費者パターンを予想していることを示唆しています。ブロッキングキューを使用した同様の方法は次のとおりです。

public class Blocking
{
   private BlockingQueue<ImmutableObject> queue = new ArrayBlockingQueue<ImmutableObject>(10);

   public void methodA() {
      queue.add(new ImmutableObject());
   }

   public ImmutableObject methodB() throws InterruptedException
   {
      return queue.take();
   }
   static class ImmutableObject
   {

   }
}

ブロッキングキューは非常に可変ですが、スレッドセーフになるように設計されているため、余分な同期なしで使用できます。渡すオブジェクトが不変である限り、デザイン全体がスレッドセーフです。

上記の例では、methodBは "take"を使用します。これは、methodAが呼び出されて何かをキューに入れるまでブロックします。または、スレッドが中断されるまで、その時点でInteruptedExceptionを介して終了します

于 2013-01-31T03:19:27.243 に答える
0

はい、データ競合の確実な可能性があります。状況は次のとおりです。

ThreadAが内部にmethodAあり、その後 ThreadBが実行されますが、前に返さmethodBれたという保証はありません。残念ながら、がまだ戻っていないのに がすでに戻ってきた場合、を取得する可能性が高くなります。methodAmethodBmethodBmethodAIndexOutOfBoundsException

// thread A invokes this method first
public static void methodA () {
    //assume control is taking time at this point, while thread B already returned!!!

    list.add(new ImmutableObject());
}

// thread B invokes this method later
public static ImmutableObject methodB () {
    return list.get(0);
}
于 2015-11-14T17:58:03.333 に答える