java - threads - CopyOnWriteArrayList arrojando CurrentModificationException
multithread demo (2)
Ocasionalmente obtengo una ConcurrentModificationException
cuando repito sobre una lista. Una búsqueda en Google me informa que probablemente sea porque estoy alterando esa lista en otro hilo mientras realizo una iteración sobre él y que para que este problema desaparezca debería usar java.util.concurrent.CopyOnWriteArrayList
....
... excepto que ya estoy.
Aparentemente, estoy haciendo algo realmente estúpido en alguna parte.
¿Alguien tiene alguna idea de cómo se podría inducir a CopyOnWriteArrayList
a lanzar una ConcurrentModificationException
? Si es importante, estoy usando Java 5.
Editar: dado que los mutadores que uso pueden ser importantes, estoy modificando esta lista de dos maneras:
- Agregar elementos al frente. (
list.add(0, newElement);
) - Usar subList para dejar que los elementos más antiguos caigan por la parte posterior. (
list = list.subList(0, MAX_LIST_SIZE);
)
¿Los que levantan banderas rojas? Si es así, ¿por qué? Tengo entendido que debido a que estas operaciones hacen una copia de la cosa primero, cualquier iterador existente estaría apuntando al original no modificado y, por lo tanto, no le importaría. ¿Tengo un agujero en mi conocimiento?
Editar 2: El código exacto que está causando el problema todavía es un poco turbio, pero al menos puedo publicar la excepción que estoy viendo:
java.util.ConcurrentModificationException
at java.util.concurrent.CopyOnWriteArrayList$COWSubList.checkForComodification(Unknown Source)
at java.util.concurrent.CopyOnWriteArrayList$COWSubList.iterator(Unknown Source)
at....
... donde apunta a una instanciación de bucle for-each en mi código.
Esa COWSubList
parece implicar que mi llamada a subList
es la raíz de mi problema; Todavía me gustaría entender por qué.
Editar 3: * facepalm *
CopyOnWriteArrayList.subList()
devuelve una List
, no una CopyOnWriteArrayList
. La lista que devuelve no está bajo ninguna obligación implícita de proporcionar ninguna de las protecciones de COWAL. Lo que hace que el uso de subList()
como este para eliminar elementos sea una muy mala idea.
No sé con certeza si este es mi culpable, pero es muy sospechoso y necesita ser corregido de todos modos.
CopyOnWriteArrayList.subLists lanza ConcurrentModificationExceptions si la lista contiene cambios desde abajo:
public class ListTest {
private static List<int[]> intList;
public static void main (String[] args) {
CopyOnWriteArrayList<Integer> cowal = new CopyOnWriteArrayList<Integer>();
cowal.add(1);
cowal.add(2);
cowal.add(3);
List<Integer> sub = cowal.subList(1, 2);
cowal.add(4);
sub.get(0); //throws ConcurrentModificationException
}
}
Sbodd tiene la respuesta correcta, pero parece que usar CopyOnWriteArrayList en lugar de ArrayList es solo un intento de enmascarar el error. El verdadero problema es un intento de modificar la lista subyacente mientras se itera sobre ella. Debe encontrar en qué parte de su código está accediendo como tal y eliminar ese uso o solucionarlo.