2009-05-08 9 views
11

私はConcurrentModificationExceptionに遭遇しました。それを見て、なぜそれが起こっているのかわかりません。例外とコレクションを変更するすべての場所を投げ面積は、私は厄介なスレッドをキャッチしようとしたConcurrentModificationExceptionをデバッグするには?

synchronized (this.locks.get(id)) { 
    ... 
} // locks is a HashMap<String, Object>; 

に囲まれているが、私は(例外にブレークポイントを設定することで)ネイルことができるすべては投げスレッドが所有しているということです他のスレッド(プログラム内に2つのスレッドがある)がスリープしている間は、モニターを停止します。


どうすればよいですか?同じようなスレッドの問題が発生したときは、通常何をしますか?

+0

[ループを取り除くときにConcurrentModificationExceptionを避けて、コレクションを反復する]の可能な複製(http://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception- when-re) – Raedwald

答えて

30

同期ブロックとは関係ありません。 ConcurrentModificationExceptionは、要素を反復処理している間にコレクションを変更するときによく発生します。

List<String> messages = ...; 
for (String message : messages) { 
    // Prone to ConcurrentModificationException 
    messages.add("A COMPLETELY NEW MESSAGE"); 
} 
1

それは(例えばforeachのループで)、それを反復しながら、動的リストを変更するときにConcurrentModificationExceptionを受信するために一般的です。あなたはどこでもそれをしていないことを確認したいかもしれません。

11

以前の投稿と同様に、エントリを削除すると同じ問題が発生する可能性があります。例:

for(String message : messages) { 
    if (condition(message)) 
    messages.remove(message); 
} 

もう1つの一般的な例は、マップをクリーンアップすることです。

この特定の問題は、Iteratorを明示的に使用して解決できます。

for(Iterator<String> iter = messages.iterator(); iter.hasNext();) { 
    String message = iter.next(); 
    if (condition(message)) 
     iter.remove(); // doesn't cause a ConcurrentModificationException 
} 
+1

iter.remove()行でConcurrentModificationExceptionが引き続き発生します。 –

+1

@ErikBあなたの問題を解決しましたか?どうやって? –

+2

@ user309483パフォーマンステストの後にCopyOnWriteArrayを使用し、パフォーマンスが私たちのニーズに悪くないことを確認しました。いくつかの場所では、toRemoveSetソリューションのifteeの記述に行ってきました。 –

4

リストからいくつかの要素を削除する必要がある場合は、削除する要素のような別のリストを保持することができます。最後にremoveAll(collection)を呼び出します。もちろん、これは膨大なデータには適していません。

5

アプリケーションが複雑すぎる場合があり、一部の機能が多すぎる副作用があります。また、おそらく別のスレッドがそのリストで何か問題を起こしている可能性があります。

私自身の問題では、別のリストを委譲する独自のリストシステムを作成しましたが、一度ロックされると他のすべての変更がConcurrentModificationExceptionをスローするため、無効な変更命令が例外で出力されます。また、上記のエラーを検出することもできます。

 
import java.util.*; 

/** 
* Created by IntelliJ IDEA. 
* User: francoiscassistat 
* Date: 12 juin 2010 
* Time: 18:20:18 
* 
* 
* Lockable list, made to debug ConcurrentModificationException on Lists. 
* The lock can be switched on/off with setLocked(boolean). 
* When locked, all write access to the list or iterators gets ConcurrentModificationException. 
* Simple usage case : 
* 
* list.setLocked(true); 
* 
* for (Object o : list.iterator()) // now this won't get ConcurrentModificationException, the other instruction that cause this will thrown the exception 
* { ... } 
* 
* list.setLocked(false); 
*/ 
public class LockableList<E> implements List<E> { 
    protected class LockableListIterator implements Iterator<E> { 
     protected Iterator<E> iterator; 

     public LockableListIterator(Iterator<E> iterator) { 
      this.iterator = iterator; 
     } 

     public boolean hasNext() { 
      return iterator.hasNext(); 
     } 

     public E next() { 
      return iterator.next(); 
     } 

     public void remove() { 
      checkLock(); 
      iterator.remove(); 
     } 
    } 

    protected class LockableListListIterator implements ListIterator<E> { 
     protected ListIterator<E> listIterator; 

     public LockableListListIterator(ListIterator<E> listIterator) { 
      this.listIterator = listIterator; 
     } 

     public boolean hasNext() { 
      return listIterator.hasNext(); 
     } 

     public E next() { 
      return listIterator.next(); 
     } 

     public boolean hasPrevious() { 
      return listIterator.hasPrevious(); 
     } 

     public E previous() { 
      return listIterator.previous(); 
     } 

     public int nextIndex() { 
      return listIterator.nextIndex(); 
     } 

     public int previousIndex() { 
      return listIterator.previousIndex(); 
     } 

     public void remove() { 
      checkLock(); 
      listIterator.remove(); 
     } 

     public void set(E e) { 
      checkLock(); 
      listIterator.set(e); 
     } 

     public void add(E e) { 
      checkLock(); 
      listIterator.add(e); 
     } 
    } 

    protected class LockableListSubList implements List<E> 
    { 
     protected List<E> list; 

     public LockableListSubList(List<E> list) { 
      this.list = list; 
     } 

     public int size() { 
      return list.size(); 
     } 

     public boolean isEmpty() { 
      return list.isEmpty(); 
     } 

     public boolean contains(Object o) { 
      return list.contains(o); 
     } 

     public Iterator<E> iterator() { 
      return new LockableListIterator(list.iterator()); 
     } 

     public Object[] toArray() { 
      return list.toArray(); 
     } 

     public <T> T[] toArray(T[] a) { 
      return list.toArray(a); 
     } 

     public boolean add(E e) { 
      checkLock(); 
      return list.add(e); 
     } 

     public boolean remove(Object o) { 
      checkLock(); 
      return list.remove(o); 
     } 

     public boolean containsAll(Collection<?> c) { 
      return list.containsAll(c); 
     } 

     public boolean addAll(Collection<? extends E> c) { 
      checkLock(); 
      return list.addAll(c); 
     } 

     public boolean addAll(int index, Collection<? extends E> c) { 
      checkLock(); 
      return list.addAll(index, c); 
     } 

     public boolean removeAll(Collection<?> c) { 
      checkLock(); 
      return list.removeAll(c); 
     } 

     public boolean retainAll(Collection<?> c) { 
      checkLock(); 
      return list.retainAll(c); 
     } 

     public void clear() { 
      checkLock(); 
      list.clear(); 
     } 

     @Override 
     public boolean equals(Object o) { 
      return list.equals(o); 
     } 

     @Override 
     public int hashCode() { 
      return list.hashCode(); 
     } 

     public E get(int index) { 
      return list.get(index); 
     } 

     public E set(int index, E element) { 
      checkLock(); 
      return list.set(index, element); 
     } 

     public void add(int index, E element) { 
      checkLock(); 
      list.add(index, element); 
     } 

     public E remove(int index) { 
      checkLock(); 
      return list.remove(index); 
     } 

     public int indexOf(Object o) { 
      return list.indexOf(o); 
     } 

     public int lastIndexOf(Object o) { 
      return list.lastIndexOf(o); 
     } 

     public ListIterator<E> listIterator() { 
      return new LockableListListIterator(list.listIterator()); 
     } 

     public ListIterator<E> listIterator(int index) { 
      return new LockableListListIterator(list.listIterator(index)); 
     } 

     public List<E> subList(int fromIndex, int toIndex) { 
      return new LockableListSubList(list.subList(fromIndex, toIndex)); 
     } 
    } 

    protected List<E> list; 
    protected boolean locked; 

    public LockableList(List<E> list) { 
     this.list = list; 
     locked = false; 
    } 

    public boolean isLocked() { 
     return locked; 
    } 

    public void setLocked(boolean locked) { 
     this.locked = locked; 
    } 

    protected void checkLock() { 
     if (locked) 
      throw new ConcurrentModificationException("Locked"); 
    } 

    public int size() { 
     return list.size(); 
    } 

    public boolean isEmpty() { 
     return list.isEmpty(); 
    } 

    public boolean contains(Object o) { 
     return list.contains(o); 
    } 

    public Iterator<E> iterator() { 
     return new LockableListIterator(list.iterator()); 
    } 

    public Object[] toArray() { 
     return list.toArray(); 
    } 

    public <T> T[] toArray(T[] a) { 
     return list.toArray(a); 
    } 

    public boolean add(E e) { 
     checkLock(); 
     return list.add(e); 
    } 

    public boolean remove(Object o) { 
     checkLock(); 
     return list.remove(o); 
    } 

    public boolean containsAll(Collection<?> c) { 
     return list.containsAll(c); 
    } 

    public boolean addAll(Collection<? extends E> c) { 
     checkLock(); 
     return list.addAll(c); 
    } 

    public boolean addAll(int index, Collection<? extends E> c) { 
     checkLock(); 
     return list.addAll(index, c); 
    } 

    public boolean removeAll(Collection<?> c) { 
     checkLock(); 
     return list.removeAll(c); 
    } 

    public boolean retainAll(Collection<?> c) { 
     checkLock(); 
     return list.retainAll(c); 
    } 

    public void clear() { 
     checkLock(); 
     list.clear(); 
    } 

    @Override 
    public boolean equals(Object o) { 
     return list.equals(o); 
    } 

    @Override 
    public int hashCode() { 
     return list.hashCode(); 
    } 

    public E get(int index) { 
     return list.get(index); 
    } 

    public E set(int index, E element) { 
     checkLock(); 
     return list.set(index, element); 
    } 

    public void add(int index, E element) { 
     checkLock(); 
     list.add(index, element); 
    } 

    public E remove(int index) { 
     checkLock(); 
     return list.remove(index); 
    } 

    public int indexOf(Object o) { 
     return list.indexOf(o); 
    } 

    public int lastIndexOf(Object o) { 
     return list.lastIndexOf(o); 
    } 

    public ListIterator<E> listIterator() { 
     return new LockableListListIterator(list.listIterator()); 
    } 

    public ListIterator<E> listIterator(int index) { 
     return new LockableListListIterator(list.listIterator(index)); 
    } 

    public List<E> subList(int fromIndex, int toIndex) { 
     return new LockableListSubList(list.subList(fromIndex, toIndex)); 
    } 
} 

だけでこのようにそれを使用します。

 
List list = new LockableList(new ArrayList(...)); 
list.setLocked(true); 

for (E e : list.iterator()) 
{ ... } 

list.setLocked(false); 

は、それが他の誰かを助けることを願っています。

2

同様の問題に対処しなければならなかったので、特定のオブジェクトで同時アクセス状況をデバッグする小さなヘルパーを作成しました。デバッガを使用すると実行時の動作が大きく変わって問題が発生しないことがあります。このアプローチは、Francoisが示したアプローチと似ていますが、もう少し一般的です。おそらくそれは誰かを助けるかもしれません:http://code.google.com/p/kongcurrent/

関連する問題