interview - Java: ConcurrentModificationException mientras se itera sobre la lista
java list (3)
Cuando ejecuto el siguiente código, obtengo ConcurrentModificationException
Collection<String> myCollection = Collections.synchronizedList(new ArrayList<String>(10));
myCollection.add("123");
myCollection.add("456");
myCollection.add("789");
for (Iterator it = myCollection.iterator(); it.hasNext();) {
String myObject = (String)it.next();
System.out.println(myObject);
myCollection.remove(myObject);
//it.remove();
}
¿Por qué recibo la excepción, aunque estoy usando Collections.synchronizedList?
Cuando cambio myCollection a
ConcurrentLinkedQueue<String> myCollection = new ConcurrentLinkedQueue<String>();
No entiendo esa excepción.
¿Cómo es ConcurrentLinkedQueue en java.util.concurrent diferente de Collections.synchronizedList?
¿Cómo es ConcurrentLinkedQueue en java.util.concurrent diferente de Collections.synchronizedList?
Tienen implementaciones diferentes y, por lo tanto, pueden elegir lanzar ConcurrentModificationException o manejar la situación que describa con elegancia. Evidentemente CLQ maneja con gracia, y ArrayList envuelto por Collections.synchronizedList (mi conjetura es que el comportamiento es ArrayList, no el de la envoltura) no.
Como dice @unbeli, elimine a través del iterador, no la colección mientras itera.
Una lista sincronizada no proporcionará una nueva implementación de Iterator
. Utilizará la implementación de la lista sincronizada . La implementación de iterator()
es:
public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user!
}
De ArrayList
:
Los iteradores devueltos por el iterador de esta clase y los métodos listIterator son rápidos : si la lista se modifica estructuralmente en cualquier momento después de que se crea el iterador, de cualquier forma excepto a través de los propios métodos remove o add del iterador, el iterador generará una
ConcurrentModificationException
Desde ConcurrentLinkedQueue#iterator
:
Devuelve un iterador sobre los elementos en esta cola en la secuencia correcta. El iterador devuelto es un iterador "débilmente consistente" que nunca arrojará
ConcurrentModificationException
, y garantiza que atravesará los elementos tal como existían en la construcción del iterador, y puede (pero no se garantiza que) reflejar cualquier modificación posterior a la construcción.
Los iteradores devueltos por las dos colecciones son diferentes por diseño .
no hagas
myCollection.remove(myObject);
hacer
it.remove();
No hay necesidad de sincronización o recopilación concurrente