Estoy usando un Collection
(un HashMap
usado indirectamente por el JPA, sucede), pero aparentemente al azar el código arroja un ConcurrentModificationException
. ¿Qué lo está causando y cómo soluciono este problema? ¿Utilizando alguna sincronización, tal vez?
Aquí está el seguimiento completo de la pila:
Exception in thread "pool-1-thread-1" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$ValueIterator.next(Unknown Source)
at org.hibernate.collection.AbstractPersistentCollection$IteratorProxy.next(AbstractPersistentCollection.java:555)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
java
exception
collections
concurrentmodification
cuerdas principales
fuente
fuente
Respuestas:
Este no es un problema de sincronización. Esto ocurrirá si la colección subyacente que se está iterando es modificada por algo que no sea el iterador en sí.
Esto arrojará un
ConcurrentModificationException
cuandoit.hasNext()
se llama por segunda vez.El enfoque correcto sería
Asumiendo que este iterador soporta la
remove()
operación.fuente
Intenta usar un en
ConcurrentHashMap
lugar de un simpleHashMap
fuente
La modificación de un
Collection
tiempo iterando a través de esoCollection
usando un noIterator
está permitido por la mayoría de lasCollection
clases. La biblioteca Java llama a un intento de modificar unCollection
tiempo mientras itera a través de ella una "modificación concurrente". Desafortunadamente, eso sugiere que la única causa posible es la modificación simultánea por múltiples hilos, pero eso no es así. Usando solo un hilo es posible crear un iterador para elCollection
(usandoCollection.iterator()
, o un bucle mejoradofor
), comenzar a iterar (usarIterator.next()
, o ingresar de manera equivalente al cuerpo delfor
bucle mejorado ), modificar elCollection
, luego continuar iterando.Para ayudar a los programadores, algunas implementaciones de esas
Collection
clases intentan detectar modificaciones concurrentes erróneas y arrojan unConcurrentModificationException
si lo detectan. Sin embargo, en general no es posible y práctico garantizar la detección de todas las modificaciones concurrentes. Por lo tanto, el uso erróneo de laCollection
no siempre resulta en un lanzamientoConcurrentModificationException
.La documentación de
ConcurrentModificationException
dice:Tenga en cuenta que
La documentación de la
HashSet
,HashMap
,TreeSet
yArrayList
clases dice lo siguiente:Tenga en cuenta de nuevo que el comportamiento "no se puede garantizar" y solo es "en el mejor esfuerzo".
La documentación de varios métodos de la
Map
interfaz dice esto:Tenga en cuenta nuevamente que solo se requiere una "base de mejor esfuerzo" para la detección, y a
ConcurrentModificationException
se sugiere explícitamente solo para las clases no concurrentes (no seguras para subprocesos).Depuración
ConcurrentModificationException
Por lo tanto, cuando ve un seguimiento de pila debido a a
ConcurrentModificationException
, no puede suponer de inmediato que la causa es el acceso no seguro de subprocesos múltiples a aCollection
. Debe examinar el seguimiento de la pila para determinar qué clase deCollection
lanzó la excepción (un método de la clase la habrá arrojado directa o indirectamente) y para quéCollection
objeto. Luego debe examinar desde dónde se puede modificar ese objeto.Collection
dentro de unfor
bucle mejorado sobreCollection
. ¡El hecho de que no vea unIterator
objeto en su código fuente no significa que no hayaIterator
allí! Afortunadamente, una de las declaraciones delfor
bucle defectuoso generalmente estará en el seguimiento de la pila, por lo que rastrear el error suele ser fácil.Collection
objeto. Tenga en cuenta que las vistas no modificables de las colecciones (como las producidas porCollections.unmodifiableList()
) retienen una referencia a la colección modificable, por lo que la iteración sobre una colección "no modificable" puede arrojar la excepción (la modificación se ha realizado en otro lugar). Otras vistas de suCollection
, como sublistas ,Map
conjuntos de entradas yMap
conjuntos de claves también conservan referencias al original (modificable)Collection
. Esto puede ser un problema incluso para un hilo seguroCollection
, comoCopyOnWriteList
; no asuma que las colecciones seguras para hilos (concurrentes) nunca pueden lanzar la excepción.Collection
pueden ser inesperadas en algunos casos. Por ejemplo,LinkedHashMap.get()
modifica su colección .Programación para evitar errores de modificación concurrentes
Cuando sea posible, limite todas las referencias a un
Collection
objeto, para que sea más fácil evitar modificaciones concurrentes. ConviertaCollection
unprivate
objeto o una variable local y no devuelva referencias aCollection
sus iteradores de los métodos. Entonces es mucho más fácil examinar todos los lugares dondeCollection
se pueden modificar. Si laCollection
van a utilizar varios subprocesos, entonces es práctico asegurarse de que los subprocesos accedanCollection
solo con la sincronización y el bloqueo adecuados.fuente
En Java 8, puede usar la expresión lambda:
fuente
Suena menos como un problema de sincronización de Java y más como un problema de bloqueo de la base de datos.
No sé si agregar una versión a todas sus clases persistentes lo resolverá, pero esa es una forma en que Hibernate puede proporcionar acceso exclusivo a las filas de una tabla.
Podría ser que el nivel de aislamiento necesita ser más alto. Si permite "lecturas sucias", tal vez necesite subir a serializable.
fuente
Pruebe CopyOnWriteArrayList o CopyOnWriteArraySet dependiendo de lo que esté tratando de hacer.
fuente
Solo doy mi ejemplo de trabajo aquí para que los novatos ahorren su tiempo:
fuente
Me encontré con esta excepción cuando intento eliminar x últimos elementos de la lista.
myList.subList(lastIndex, myList.size()).clear();
fue la única solución que funcionó para mí.fuente