19

ArrayLists の ArrayList をスレッドセーフにする必要があります。また、クライアントにコレクションを変更させることもできません。変更不可能なラッパーはスレッド セーフになりますか、それともコレクションに 2 つのラッパーが必要ですか?

4

9 に答える 9

10

場合によります。ラッパーは、コレクション内のオブジェクトではなく、ラップするコレクションへの変更のみを防止します。ArrayLists の ArrayList がある場合、グローバル List とその要素 Lists のそれぞれを個別にラップする必要があり、それらのリストの内容に対して何かを行う必要がある場合もあります。最後に、元のリスト オブジェクトが変更されていないことを確認する必要があります。これは、ラッパーは元のオブジェクトへの変更ではなく、ラッパー参照による変更のみを防止するためです。

この場合、同期ラッパーは必要ありません。

于 2008-09-17T21:54:55.327 に答える
5

関連トピックについて - スレッド セーフを実現するために同期コレクションを使用することを提案するいくつかの返信を見てきました。コレクションの同期バージョンを使用しても、「スレッド セーフ」にはなりません。ただし、2 つの操作を組み合わせる場合、各操作 (挿入、カウントなど) はミューテックスによって保護されますが、それらがアトミックに実行されるという保証はありません。たとえば、次のコードはスレッド セーフではありません (同期キューを使用しても)。

if(queue.Count > 0)
{
   queue.Add(...);
}
于 2008-09-18T09:44:09.243 に答える
2

変更不可能なラッパーは、それが適用されるリストの構造への変更のみを防ぎます。このリストに他のリストが含まれていて、これらのネストされたリストを変更しようとするスレッドがある場合、同時変更のリスクから保護されません。

于 2008-09-17T21:52:17.830 に答える
1

不変オブジェクトは定義上、スレッド セーフであるため (誰も元のコレクションへの参照を保持していないと仮定)、同期は必要ありません

Collections.unmodifiableList() を使用して外側の ArrayList をラップすると、クライアントがその内容を変更できなくなります (したがって、スレッド セーフになります) が、内側の ArrayList は依然として変更可能です。

Collections.unmodifiableList() を使用して内部の ArrayLists をラップすると、クライアントが内容を変更するのを防ぎます (したがって、スレッドセーフになります)。これが必要です。

この解決策が問題 (オーバーヘッド、メモリ使用量など) を引き起こすかどうかをお知らせください。他の解決策が問題に適用できる場合があります。:)

編集: もちろん、リストが変更された場合、それらはスレッドセーフではありません。これ以上の編集は行われないと想定しました。

于 2008-09-18T19:54:30.693 に答える
1

Collections のソースを見ると、Unmodifiable では同期されていないように見えます。

static class UnmodifiableSet<E> extends UnmodifiableCollection<E>
                 implements Set<E>, Serializable;

static class UnmodifiableCollection<E> implements Collection<E>, Serializable;

同期クラスラッパーには、同期部分を実行するためのミューテックスオブジェクトが含まれているため、両方を取得するには両方を使用する必要があるようです。または自分で巻いてください!

于 2008-09-17T21:53:53.753 に答える
1

変更不可能なビューが安全に発行され、変更不可能なビューの発行後に変更可能なオリジナルが (コレクションに再帰的に含まれるすべてのオブジェクトを含めて) 決して変更されない場合、スレッドセーフになります。

オリジナルを変更し続けたい場合は、コレクションのオブジェクト グラフの防御的なコピーを作成し、その変更不可能なビューを返すか、本質的にスレッド セーフなリストを使用して開始し、変更不可能なビューを返すことができます。それ。

後で同期されていない theList にアクセスするつもりなら、 unmodifiableList(synchonizedList(theList)) を返すことはできません。変更可能な状態が複数のスレッド間で共有されている場合、すべてのスレッドはその状態にアクセスするときに同じロックで同期する必要があります。

于 2008-09-21T13:08:47.733 に答える
1

UnmodifiableList ラッパーは ArrayList を最終フィールドに格納するため、ラッパーの読み取りメソッドは、ラッパーが作成された後にリストが変更されない限り、ラッパーが構築されたときと同じようにリストを参照すると思います。ラッパー内の変更可能な ArrayLists が変更されない限り (ラッパーが保護することはできません)。

于 2008-09-17T23:51:55.967 に答える
0

あなたが何をしようとしているのか理解できたかどうかはわかりませんが、ほとんどの場合、答えは「いいえ」です。

ArrayList の ArrayList とその両方をセットアップする場合、作成後に外側と内側のリストを変更することはできません (作成中は、1 つのスレッドのみが内側と外側のリストにアクセスできます)。それらはおそらくラッパーによってスレッド セーフです (両方の場合、外側および内側のリストは、それらを変更できないような方法でラップされます)。ArrayList に対するすべての読み取り専用操作は、ほとんどの場合、スレッドセーフです。ただし、Sun はそれらがスレッドセーフであることを保証していません (読み取り専用操作に対してもそうではありません)。例)。

于 2008-09-17T21:59:13.803 に答える
0

これは、次の場合に必要です。

  1. 元の変更可能なリストへの参照がまだあります。
  2. リストはイテレータを介してアクセスされる可能性があります。

インデックスのみで ArrayList から読み取る場合は、これがスレッドセーフであると想定できます。

疑わしい場合は、同期ラッパーを選択してください。

于 2008-09-17T21:58:12.997 に答える