1

次のコードを検討し、list が同期された List であると仮定します。

List list = Collections.synchronizedList(new ArrayList());

if(!list.contains(element)){
       list.add(element)
}

上記のコード フラグメントは、完全にスレッド セーフにするために外部で同期する (ロックで保護する) 必要があることを知っています。

4

5 に答える 5

3

実はたくさんあります。が評価されている間にリストが変更される可能性がありcontainsます。到達するまでに、add誰かがその要素を追加し、再度追加する可能性があります。さらに、同期がないと、他のスレッドによる書き込みがスレッドによって部分的に監視されるか、順不同で監視されるか、まったく監視されない可能性があるため、全体が奇妙な方法で崩壊する可能性があります。

containsとがそれ自体でアトミック (同期化) されている場合add、 と の呼び出しの間に明確に定義された競合が少なくとも 1 つcontainsありaddます。

于 2012-06-29T13:08:27.997 に答える
2

2 つのスレッドがチェックを実行し、両方が条件ステートメントに入ると仮定します。次に、両方が同じ要素をリストに追加しますが、これは意図した動作ではありません。そうじゃない?

于 2012-06-29T13:06:27.103 に答える
2

2 つのスレッドがあるとします。

A: if(!list.contains(element)){ // false
B: if(!list.contains(element)){ // false
A:     list.add(element) // add once
B:     list.add(element) // add a second time.

もちろん、簡単な解決策は Set を使用することです。例えば

Set<E> set = Collections.newSetFromMap(new ConcurrentHashMap<E, Boolean>());

set.add(element);
于 2012-06-29T13:40:50.207 に答える
0

リストを取得してから再保存するまでの間に競合状態が発生します(ファイルの例に保存する場合)。

例: ファイルには A が含まれています

  • スレッド 1 が A を取得
  • スレッド 1 は B を A に追加します
  • スレッド 2 が A を取得
  • スレッド 1 は AB をファイルに保存します
  • スレッド 2 は C を A に追加します
  • スレッド 2 AC をファイルに保存

読み取りファイルには AC が含まれ、スレッド 1 が行った作業は失われます

于 2012-06-29T13:07:07.400 に答える
0

list.contains(element)私の見方では、 yieldがfalseで、別のスレッドがその後要素を追加するが、最初のスレッドで追加する呼び出しの前に、競合状態が発生します。

于 2012-06-29T13:07:59.907 に答える