2009-05-08 21 views
11

Me encontré con ConcurrentModificationException y al verlo no puedo ver la razón por la que está sucediendo; la zona lanzar la excepción y todos los lugares que modifican la colección están rodeados porCómo depurar ConcurrentModificationException?

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

Traté de coger el hilo molesto, pero todo lo que pude clavar (mediante el establecimiento de un punto de interrupción en la excepción) es que el hilo de lanzamiento posee el monitor mientras que el otro hilo (hay dos hilos en el programa) duerme.


¿Cómo debo proceder? ¿Qué sueles hacer cuando te encuentras con problemas similares de enhebrado?

+0

Posible duplicado de [iteración a través de una recopilación, evitando ConcurrentModificationException al eliminar en bucle] (http://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception- when-re) – Raedwald

Respuesta

30

Puede no tener nada que ver con el bloque de sincronización. ConcurrentModificationException menudo ocurren cuando está modificando una colección mientras está iterando sobre sus elementos.

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

Es común para recibir una ConcurrentModificationException al modificar una lista dinámica mientras iterar sobre ella (en un foreach-loop por ejemplo). Es posible que desee asegurarse de que no está haciendo eso en ninguna parte.

11

Similar a una publicación anterior, puede obtener el mismo problema si elimina una entrada. p.

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

Otro ejemplo común es la limpieza de un mapa.

Este problema en particular se puede resolver usando un iterador explícitamente.

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

Aún obtengo una ConcurrentModificationException en la línea iter.remove(). –

+1

@ErikB ¿Resolvió su problema? ¿Cómo? –

+2

@ user309483 Utilicé CopyOnWriteArray después de las pruebas de rendimiento y encontré que el rendimiento no es malo para nuestras necesidades. En algunos lugares elegimos la solución toRemoveSet si se menciona. –

4

si necesita eliminar algunos elementos de su lista. Puede mantener otra lista como elementos para eliminar. Y finalmente llame a removeAll (colección). Por supuesto, esto no es bueno para datos enormes.

5

En ocasiones, su aplicación puede ser demasiado compleja y algunas funciones pueden tener demasiado efecto secundario. Además, tal vez otro hilo realmente está haciendo algo mal con esa lista y no puedes encontrar dónde fácilmente.

Para mi propio problema, he escrito mi propio sistema de lista que delega otra lista y, una vez bloqueado, todas las demás modificaciones arrojan ConcurrentModificationException, por lo que la instrucción de modificación incorrecta obtendrá salida con la excepción. También puede detectar los errores descritos anteriormente.

 
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 con utilizar de esta manera:

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

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

list.setLocked(false); 

espero que pueda ayudar a alguien más.

2

Habiendo tenido que lidiar con problemas similares, escribí un pequeño ayudante para depurar situaciones de acceso simultáneo en ciertos objetos (a veces el uso de un depurador modifica el comportamiento del tiempo de ejecución tanto que el problema no ocurre). El enfoque es similar al que mostró Francois, pero un poco más genérico. Tal vez ayuda a alguien: http://code.google.com/p/kongcurrent/