Estoy usando un Collection(un HashMapusado 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
ConcurrentModificationExceptioncuandoit.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
ConcurrentHashMaplugar de un simpleHashMapfuente
La modificación de un
Collectiontiempo iterando a través de esoCollectionusando un noIteratorestá permitido por la mayoría de lasCollectionclases. La biblioteca Java llama a un intento de modificar unCollectiontiempo 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 delforbucle mejorado ), modificar elCollection, luego continuar iterando.Para ayudar a los programadores, algunas implementaciones de esas
Collectionclases intentan detectar modificaciones concurrentes erróneas y arrojan unConcurrentModificationExceptionsi 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 laCollectionno siempre resulta en un lanzamientoConcurrentModificationException.La documentación de
ConcurrentModificationExceptiondice:Tenga en cuenta que
La documentación de la
HashSet,HashMap,TreeSetyArrayListclases 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
Mapinterfaz dice esto:Tenga en cuenta nuevamente que solo se requiere una "base de mejor esfuerzo" para la detección, y a
ConcurrentModificationExceptionse sugiere explícitamente solo para las clases no concurrentes (no seguras para subprocesos).Depuración
ConcurrentModificationExceptionPor 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 deCollectionlanzó la excepción (un método de la clase la habrá arrojado directa o indirectamente) y para quéCollectionobjeto. Luego debe examinar desde dónde se puede modificar ese objeto.Collectiondentro de unforbucle mejorado sobreCollection. ¡El hecho de que no vea unIteratorobjeto en su código fuente no significa que no hayaIteratorallí! Afortunadamente, una de las declaraciones delforbucle defectuoso generalmente estará en el seguimiento de la pila, por lo que rastrear el error suele ser fácil.Collectionobjeto. 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 ,Mapconjuntos de entradas yMapconjuntos 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.Collectionpueden 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
Collectionobjeto, para que sea más fácil evitar modificaciones concurrentes. ConviertaCollectionunprivateobjeto o una variable local y no devuelva referencias aCollectionsus iteradores de los métodos. Entonces es mucho más fácil examinar todos los lugares dondeCollectionse pueden modificar. Si laCollectionvan a utilizar varios subprocesos, entonces es práctico asegurarse de que los subprocesos accedanCollectionsolo 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