Como depurar ConcurrentModificationException?

Eu encontrei ConcurrentModificationException e olhando para ele não consigo ver a razão pela qual está acontecendo; a área jogando a exceção e todos os lugares que modificam a coleção são cercados por

synchronized (this.locks.get(id)) { ... } // locks is a HashMap; 

Eu tentei pegar o segmento traquinas, mas tudo que eu poderia pregar (definindo um ponto de interrupção na exceção) é que o thread de lançamento possui o monitor enquanto o outro thread (há dois threads no programa) dorme.

Como devo proceder? O que você costuma fazer quando encontra problemas de segmentação semelhantes?

Pode não ter nada a ver com o bloco de synchronization. ConcurrentModificationException s geralmente ocorre quando você está modificando uma coleção enquanto está interagindo com seus elementos.

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

Semelhante a um post anterior, você pode obter o mesmo problema se excluir uma input. por exemplo

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

Outro exemplo comum é a limpeza de um mapa.

Esse problema específico pode ser resolvido usando um Iterador explicitamente.

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

Às vezes seu aplicativo pode ser complexo demais e algumas funções podem ter muito efeito colateral. Além disso, talvez outro tópico esteja realmente fazendo algo errado com essa lista e você não possa encontrar onde facilmente.

Para meu próprio problema, eu escrevi meu próprio sistema de lista que delega outra lista e, uma vez bloqueado, todas as outras modificações lançam ConcurrentModificationException, portanto, a instrução de modificação incorreta obterá na saída com a exceção. Também pode detectar erros descritos acima.

 import java.util. *;

 / **
  * Criado por IntelliJ IDEA.
  * Usuário: francoiscassistat
  * Data: 12 de junho de 2010
  * Hora: 18:20:18
  *
  *
  * Lista de bloqueio, feita para depurar ConcurrentModificationException em listas.
  * O bloqueio pode ser ligado / desligado com setLocked (booleano).
  * Quando bloqueado, todo o access de gravação à lista ou iteradores recebe ConcurrentModificationException.
  * Caso de uso simples:
  *
  * list.setLocked (true);
  *
  * para (Objecto: list.iterator ()) // agora isto não irá obter ConcurrentModificationException, a outra instrução que causa isto irá lançar a exceção
  * {...}
  *
  * list.setLocked (false);
  * /
 class pública LockableList  implementa lista  {
     class protegida LockableListIterator implementa o Iterador  {
         Iterador protegido  iterador;

         LockableListIterator público (Iterator  iterador) {
             this.iterator = iterador;
         }

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

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

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

     class protegida LockableListListIterator implementa ListIterator  {
         ListIterator  listIterator protegido;

         LockableListListIterator público (ListIterator  listIterator) {
             this.listIterator = listIterator;
         }

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

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

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

     class protegida LockableListSubList implementa a lista 
     {
         lista de lista protegida ;

         LockableListSubList público (lista  lista) {
             this.list = list;
         }

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

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

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

         Iterador público  iterador () {
             return new LockableListIterator (list.iterator ());
         }

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

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

         adição booleana pública (Ee) {
             checkLock ();
             return list.add (e);
         }

         remoção booleana pública (object o) {
             checkLock ();
             lista de retorno.remove (o);
         }

         public boolean containsAll (Coleção  c) ​​{
             return list.containsAll (c);
         }

         public boolean addAll (Coleção  c) {
             checkLock ();
             return list.addAll (c);
         }

         public boolean addAll (índice int, Collection  c) {
             checkLock ();
             return list.addAll (índice, c);
         }

         public boolean removeAll (Coleção  c) ​​{
             checkLock ();
             lista de retorno.removeAll (c);
         }

         public boolean retainAll (Coleção  c) ​​{
             checkLock ();
             return list.retainAll (c);
         }

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

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

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

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

         conjunto público E (índice int, elemento E) {
             checkLock ();
             return list.set (index, element);
         }

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

         public E remove (int index) {
             checkLock ();
             lista de retorno.remove (índice);
         }

         public int indexOf (Object o) {
             lista de retorno.indexOf (o);
         }

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

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

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

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

     lista de lista protegida ;
     bloqueado booleano protegido;

     LockableList público (lista  lista) {
         this.list = list;
         bloqueado = falso;
     }

     public boolean isLocked () {
         retorno trancado;
     }

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

     protected void checkLock () {
         se (bloqueado)
             lançar novo ConcurrentModificationException ("Locked");
     }

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

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

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

     Iterador público  iterador () {
         return new LockableListIterator (list.iterator ());
     }

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

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

     adição booleana pública (Ee) {
         checkLock ();
         return list.add (e);
     }

     remoção booleana pública (object o) {
         checkLock ();
         lista de retorno.remove (o);
     }

     public boolean containsAll (Coleção  c) ​​{
         return list.containsAll (c);
     }

     public boolean addAll (Coleção  c) {
         checkLock ();
         return list.addAll (c);
     }

     public boolean addAll (índice int, Collection  c) {
         checkLock ();
         return list.addAll (índice, c);
     }

     public boolean removeAll (Coleção  c) ​​{
         checkLock ();
         lista de retorno.removeAll (c);
     }

     public boolean retainAll (Coleção  c) ​​{
         checkLock ();
         return list.retainAll (c);
     }

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

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

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

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

     conjunto público E (índice int, elemento E) {
         checkLock ();
         return list.set (index, element);
     }

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

     public E remove (int index) {
         checkLock ();
         lista de retorno.remove (índice);
     }

     public int indexOf (Object o) {
         lista de retorno.indexOf (o);
     }

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

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

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

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

Basta usá-lo assim:

 Listar lista = new LockableList (new ArrayList (...));
 list.setLocked (true);

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

 list.setLocked (false);

Espero que possa ajudar outra pessoa.

se você precisar excluir alguns elementos da sua lista. Você pode manter outra lista como elementos a serem removidos. E finalmente, chame removeAll (coleção). Claro que isso não é bom para dados enormes.

Tendo que lidar com problemas semelhantes, escrevi um pequeno auxiliar para depurar situações de access simultâneo em determinados objects (às vezes, usar um depurador modifica o comportamento do tempo de execução de forma que o problema não ocorra). A abordagem é semelhante à que François mostrou, mas um pouco mais genérica. Talvez isso ajude alguém: http://code.google.com/p/kongcurrent/

É comum receber um ConcurrentModificationException ao modificar uma lista dinâmica enquanto iterar sobre ela (em um foreach-loop, por exemplo). Você pode querer ter certeza de que não está fazendo isso em lugar algum.