10

これを繰り返すと、なぜConcurrentModificationExceptionが発生するのかわかりませんmultimap。次のエントリを読みましたが、すべてを理解したかどうかはわかりません。同期ブロックを追加しようとしました。しかし、私の疑問は、何といつ同期するかです。

multimapフィールドであり、次のように作成されます。

private Multimap<GenericEvent, Command> eventMultiMap =   
   Multimaps.synchronizedMultimap(HashMultimap.<GenericEvent, Command> create());

そしてこのように使用されます:

eventMultiMap.put(event, command);

そしてこのように(私は地図上でこの部分を同期しようとしましたが、成功しませんでした)

for (Entry<GenericEvent, Command> entry : eventMultiMap.entries()) {
    if (entry.getValue().equals(command)) {
        eventMultiMap.remove(entry.getKey(), entry.getValue());
        nbRemoved++;
    }
}
4

5 に答える 5

11

コレクションを繰り返し処理しているときにコレクションで remove を呼び出すと、すべてが同じスレッドで行われたとしても、毎回 ConcurrentModificationException が発生します。正しいことは、明示的なイテレータを取得して、その上で .remove() を呼び出すことです。

編集:あなたの例を変更する:

Iterator<Map.Entry<GenericEvent, Command>> i = eventMultiMap.entries().iterator();
while (i.hasNext()) {
    if (i.next().getValue().equals(command)) {
        i.remove();
        nbRemoved++;
    }
}
于 2009-10-15T12:56:02.320 に答える
5

他のスレッドが干渉することなく、マルチマップをトラバースするときにをもたらす別の落とし穴については、このブログ投稿を参照することをお勧めします。ConcurrentModificationExceptionつまり、マルチマップのキーをトラバースし、各キーに関連付けられた値のそれぞれのコレクションにアクセスし、そのようなコレクションからいくつかの要素を削除した場合、その要素がたまたまConcurrentModificationExceptionアクセスしようとしたときに取得するコレクションの最後である場合次のキー-コレクションを空にするとキーが削除され、マルチマップのキーセットが構造的に変更されるためです。

于 2010-01-23T00:50:00.413 に答える
4

このロジックの実行中に別のスレッドがマルチマップを変更できる場合は、MHarris のコードに同期ブロックを追加する必要があります。

synchronized (eventMultimap) {
  Iterator<Entry<GenericEvent, Command>> i = eventMultiMap.entries.iterator();
  while (i.hasNext()) {
    if (i.next().getValue().equals(command)) {
        i.remove();
        nbRemoved++;
    }
  }
}

または、次のようにイテレータを省略できます。

synchronized (eventMultimap) {
  int oldSize = eventMultimap.size();
  eventMultimap.values().removeAll(Collections.singleton(command));
  nbRemoved = oldSize - eventMultimap.size();
}

removeAll() 呼び出しは同期を必要としません。ただし、同期ブロックを省略すると、マルチマップが removeAll() 呼び出しといずれかの size() 呼び出しの間で変更され、nbRemoved の値が正しくなくなる可能性があります。

コードがシングルスレッドで、ConcurrentModificationException 呼び出しを回避したいだけの場合は、Multimaps.synchronizedMultimap および同期 (eventMultimap) ロジックを省略できます。

于 2009-11-04T03:37:43.560 に答える
1

Multimap.values().iterator()キーを気にしない方がいいです。また、読み取り/書き込みに効果的な優先順位を付けることができないため、可能な限り同期ブロックを使用しないようにする必要があります。

ReadWriteLock lock = new ReentrantReadWriteLock();
Lock writeLock = lock.writeLock(); 

public void removeCommands(Command value) {
  try {
    writeLock.lock();
    for (Iterator<Command> it = multiMap.values().iterator(); it.hasNext();) {
      if (it.next() == value) {
        it.remove();
      }
    }
  } finally {
    writeLock.unlock();
  }
}
于 2013-12-14T01:18:28.870 に答える