2009-05-08 27 views
11

Ho riscontrato ConcurrentModificationException e guardandolo non riesco a vedere il motivo per cui sta accadendo; l'area lanciando l'eccezione e tutti i luoghi che modificano la collezione sono circondati daCome eseguire il debug di ConcurrentModificationException?

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

ho cercato di prendere il filetto fastidioso, ma tutto quello che potevo inchiodare (impostando un punto di interruzione nel eccezione) è che il filo lancio possiede il monitor mentre l'altro thread (ci sono due thread nel programma) dorme.


Come devo procedere? Cosa fai di solito quando incontri problemi di threading simili?

+0

Possibile duplicato di [Iterazione attraverso una raccolta, evitando ConcurrentModificationException durante la rimozione in loop] (http://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception- al momento) – Raedwald

risposta

30

Potrebbe non avere nulla a che fare con il blocco di sincronizzazione. ConcurrentModificationException s si verificano spesso quando si modifica una raccolta mentre si sta iterando sui suoi elementi.

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

È comune per ricevere un ConcurrentModificationException quando si modifica un elenco dinamico mentre iterando su di esso (in un foreach-loop per esempio). Potresti voler assicurarti di non farlo da nessuna parte.

11

Simile a un post precedente, è possibile ottenere lo stesso problema se si elimina una voce. ad es.

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

Un altro esempio comune è la pulizia di una mappa.

Questo particolare problema può essere risolto utilizzando un Iterator in modo esplicito.

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

Ricevo ancora una ConcurrentModificationException sulla riga iter.remove(). –

+1

@ErikB Hai risolto il tuo problema? Come? –

+2

@ user309483 Ho usato CopyOnWriteArray dopo che i test delle prestazioni e il rilevamento delle prestazioni non sono stati negativi per le nostre esigenze. In alcuni punti siamo andati con la soluzione toRemoveSet che menziona iftee. –

4

se è necessario eliminare alcuni elementi dall'elenco. È possibile gestire un altro elenco come elementi da rimuovere. E infine chiama removeAll (collection). Ovviamente questo non va bene per i dati enormi.

5

A volte la tua applicazione potrebbe essere complessa e troppo complessa e alcune funzioni potrebbero avere un effetto collaterale eccessivo. Inoltre, forse un altro thread sta davvero facendo qualcosa di sbagliato in quella lista e non riesci a trovarlo facilmente.

Per il mio problema, ho scritto il mio sistema di liste che delega un altro elenco e, una volta bloccato, tutte le altre modifiche generano ConcurrentModificationException, quindi l'istruzione di modifica errata verrà emessa con l'eccezione. Può anche rilevare gli errori descritti sopra.

 
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)); 
    } 
} 

Basta usare in questo modo:

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

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

list.setLocked(false); 

Spero che possa aiutare qualcun altro.

2

Avendo avuto a che fare con problemi simili ho scritto un piccolo helper per eseguire il debug di situazioni di accesso concorrenti su determinati oggetti (a volte l'uso di un debugger modifica il comportamento di runtime tanto che il problema non si verifica). L'approccio è simile a quello mostrato da Francois, ma un po 'più generico. Forse aiuta qualcuno: http://code.google.com/p/kongcurrent/