util concurrentmodificationexception java concurrentmodification

concurrentmodificationexception - iterator java



Excepción de modificación concurrente (9)

Tengo este pequeño fragmento de código y me da la excepción de modificación simultánea. No puedo entender por qué sigo obteniéndolo, aunque no veo que se lleven a cabo modificaciones concurrentes.

import java.util.*; public class SomeClass { public static void main(String[] args) { List<String> s = new ArrayList<>(); ListIterator<String> it = s.listIterator(); for (String a : args) s.add(a); if (it.hasNext()) String item = it.next(); System.out.println(s); } }


No puedo entender por qué sigo obteniéndolo, aunque no veo que se lleven a cabo modificaciones concurrentes.

Entre la creación del iterador y el uso del iterador, usted agregó argumentos a la lista que se va a iterar. Esta es una modificación concurrente.

ListIterator<String> it = s.listIterator(); for (String a : args) s.add(a); // concurrent modification here if (it.hasNext()) String item = it.next(); // exception thrown here

Crea el iterador DESPUÉS de que hayas terminado de agregar elementos a la lista:

for (String a : args) s.add(a); ListIterator<String> it = s.listIterator(); if (it.hasNext()) String item = it.next();


ConcurrentModificationException puede surgir en un entorno de subproceso único y en un entorno de múltiples subprocesos . La principal pega es que todos los iteradores de propósito general (como el que se usa en ArrayList) son todos los iteradores de FailFast , que fracasan cuando intentamos modificar una lista si un iterador ya está iterando sobre ella. Solución -> Utilice CopyOnWriteArrayList si el requisito lo necesita en lugar de utilizar ArrayList.

Para una demostración completa de esto, se puede usar el código mencionado a continuación. Solo tenemos que cambiar la implementación de CopyOnWriteArrayList a ArrayList.

import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * @author narif * */ public class TestApp { /** * @param args */ public static void main(String[] args) { List<String> testList = new ArrayList<>(); testList.add("abc"); testList.add("abc"); testList.add("abc"); testList.add("abc"); testList.add("abc"); testList.add("abc"); testList.add("abc"); testList.add("abc"); testList.add("abc"); testList.add("abc"); testList.add("abc"); testList.add("abc"); testList.add(6, "abcAtindex6"); int size = testList.size(); System.out.println("The Current List (ArrayList) is: " + testList); System.out.println("The size of the List (ArrayList) is: " + size); /* Comment the below lines to get the ConcurrentModificationException */ testList = new CopyOnWriteArrayList<>(testList); for (String value : testList) { System.out.println("The Value from ForEach Loop is: " + value); /* * Concurrent modification is happening here * One iterator is iterating over the list while we are trying to add new values to * the list so the results of the iteration are undefined under these circumstances. * So teh fail fast iterators will fail and will throw the ConcurrentModificationException. */ testList.add("valueFromForLoop"); testList.add("anotherValueFromForEachLoop"); } Iterator<String> it = testList.iterator(); while (it.hasNext()) { String abc = it.next(); System.out.println(abc); testList.add("Value from Iterator1"); testList.add("Value from Iterator2"); testList.add("Value from Iterator3"); testList.add("Value from Iterator4"); } System.out.println("Did the modificationa and all after conevrting the ArrayList to CopyOnWriteArrayList."); System.out.println("Calling the method to get the new List.."); testList = new CopyOnWriteArrayList<>(getTheList(testList)); for (String value : testList) { System.out.println("The value returned from method is : " + value); } } private static List<String> getTheList(List<String> pList) { List<String> list = new CopyOnWriteArrayList<>(pList); int i = 0; for (String lValue : list) { System.out.println("The list Passed is " + list); i++; list.add("localVaueFromMethod" + i); list.removeAll(pList); } return list; } }

Para obtener más inifo siga este enlace, esto puede ser de mucha ayuda. ConcurrentModificationException Java Docs


Desde JavaDoc: para ConcurrentModificatoinException: "generalmente no es posible que un hilo modifique una Colección mientras otro hilo lo itera".

Simplemente significa que si todavía tiene un iterador abierto, no tiene permitido modificar la lista porque el ciclo del iterador se romperá. Intente mover ListIterator<String> it = s.listIterator(); hasta después del ciclo for.


Eche un vistazo a la página de documentation Oracle.

public class ConcurrentModificationException extends RuntimeException

Esta excepción puede ser lanzada por métodos que han detectado la modificación concurrente de un objeto cuando tal modificación no es permisible

Tenga en cuenta que esta excepción no siempre indica que un objeto ha sido modificado simultáneamente por un hilo diferente. Si un único hilo emite una secuencia de invocaciones de métodos que viola el contrato de un objeto, el objeto puede arrojar esta excepción. Por ejemplo, si un hilo modifica una colección directamente mientras itera sobre la colección con un iterador de fail-fast, el iterador aplicará esta excepción .

En su caso, ha modificado la colección después de crear el iterador y, por lo tanto, ha encontrado la excepción.

Si cambia su código según la respuesta de Stephen C , no obtendrá este error.


Esto no funcionó:

LinkedList<String> linkedList = new LinkedList<String>(); ListIterator listIterator = linkedList.listIterator(); linkedList.add("aa"); linkedList.add("bb");

Esto funcionó:

LinkedList<String> linkedList = new LinkedList<String>(); linkedList.add("aa"); linkedList.add("bb"); ListIterator listIterator = linkedList.listIterator();


No se le permite continuar iterando sobre un iterador después de que se modifique la lista subyacente. Aquí crea el iterador antes de agregar algunos elementos a s , y luego procede a hacer un hasNext() y un next() después de las adiciones, lo que lleva a la ConcurrentModificationException


Para evitar la ConcurrentModificationException , debe escribir su código de esta manera:

import java.util.*; public class SomeClass { public static void main(String[] args) { List<String> s = new ArrayList<String>(); for(String a : args) s.add(a); ListIterator<String> it = s.listIterator(); if(it.hasNext()) { String item = it.next(); } System.out.println(s); } }

Un java.util.ListIterator permite modificar una lista durante la iteración, pero no entre crearla y usarla.


Si las soluciones anteriores no funcionan correctamente. Puede usar old for-loop para iterar una Lista al mismo tiempo agregar nuevos elementos. Vea el ejemplo a continuación:

import java.util.*; public class SomeClass { public static void main(String[] args) { ArrayList<AClass> aList = new ArrayList<AClass>(); // we will iterate this // this will cause ConcurrentModificationException. // Since we are iterating the list, at the same time modifying it. /*for(AClass a: aList){ aList.add(someMethod(a)); }*/ // old fashion for-loop will help int limit = aList.size(); for(int i=0; ctr<limit; ++i){ AClass a = aList.get(i); aList.add(someMethod(a)); } } }


para entender esto, veamos el origen de la implementación de HashMap:

public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable{

que contiene HashIterator de la siguiente manera:

private abstract class HashIterator { ... int expectedModCount = modCount; ... HashMapEntry<K, V> nextEntry() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); .... }

cada vez que creas un iterador:

  • se crea un contador expectedModCount y se establece en el valor de modCount como punto de control de entrada
  • ModCount se incrementa en casos de uso put / get (add / remove)
  • El método nextEntry de iterator está comprobando este valor con el modCount actual si son diferentes. La excepción de modificación simultánea es throw

para evitar esto, puede:

  • convertir mapa a una matriz (no recomendado para mapas grandes)
  • utilizar el mapa de concurrencia o las clases de lista ( CopyOnWriteArrayList / ConcurrentMap )
  • mapa de bloqueo (este enfoque elimina los beneficios del multihilo)

esto le permitirá iterar y agregar o eliminar elementos al mismo tiempo sin generar una excepción

El mapa de concurrencia / iterador de lista es un iterador "débilmente consistente" que nunca arrojará ConcurrentModificationException, y garantiza atravesar elementos tal como existían al construir el iterador, y puede (pero no se garantiza que) reflejar cualquier modificación posterior a la construcción.

Más información sobre CopyOnWriteArrayList