concurrentmodificationexception java client arraylist concurrentmodification

java.util.ConcurrentModificationException en ArrayList



concurrentmodificationexception arraylist (2)

Necesita eliminar del iterador no la colección. En su lugar, se vería así:

Iterator<User> it = users.iterator(); while (it.hasNext()) { User user = it.next(); if (!connectedUsers.contains(user)) { it.remove(); clients.remove(user); } }

Tengo una clase de Servidor y un Temporizador dentro de ella que se supone que limpia los clientes muertos (clientes que se bloquearon). Seguí el ejemplo siguiente al bloquear la colección cuando el temporizador itera sobre los usuarios, pero sigo recibiendo esta excepción (después de bloquear un cliente conectado).

http://www.javaperformancetuning.com/articles/fastfail2.shtml

List<User> users; List<User> connectedUsers; ConcurrentMap<User, IClient> clients; ... users = Collections.synchronizedList(new ArrayList<User>()); connectedUsers = new ArrayList<User>(); clients = new ConcurrentHashMap<User, IClient>(); timer = new Timer(); timer.schedule(new ClearDeadClients(), 5000, 5000); ... class ClearDeadClients extends TimerTask { public void run() { synchronized (users) { Iterator<User> it = users.iterator(); while (it.hasNext()) { User user = it.next(); // Throws exception if (!connectedUsers.contains(user)) { users.remove(user); clients.remove(user); } } } connectedUsers.clear(); } }


No puede modificar una colección mientras la itera; desafortunadamente lo hace aquí con los users , y ConcurrentModificationException es el resultado. De los propios javadocs de ArrayList:

Los iteradores devueltos por los métodos listIterator y listIterator esta clase no 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 emitirá una ConcurrentModificationException . Por lo tanto, frente a la modificación concurrente, el iterador falla rápida y limpiamente, en lugar de arriesgarse a un comportamiento arbitrario y no determinista en un tiempo indeterminado en el futuro.

Para solucionar esta situación particular, podría utilizar el método remove() propio del iterador, reemplazando esta línea:

users.remove(user);

con

it.remove();

Esta última operación elimina de la colección el último elemento que devolvió el iterador. (Este uso evita la excepción porque el iterador es consciente del cambio y es capaz de garantizar que sea seguro; con las modificaciones externas, el iterador no tiene forma de saber si el estado de su recorrido transversal es constante, por lo que falla rápidamente).

En algunas situaciones, esta eliminación inmediata puede no ser viable, en cuyo caso hay tres enfoques generales alternativos:

  1. Tome una copia de la colección (los users en este caso), repita la copia y elimine los elementos del original .
  2. Durante la iteración, construya un conjunto de elementos para eliminar y luego realice una eliminación masiva después de que la iteración se haya completado.
  3. Use una implementación de List que pueda tratar con modificaciones simultáneas, como CopyOnWriteArrayList

Esta es una pregunta bastante común: consulte también (por ejemplo) la lista de bucles con la pregunta de eliminar para obtener otras respuestas.