java - ConcurrentModificationException y un HashMap
hibernate jpa (5)
Estoy usando objetos persistentes usando JPA. El objeto principal tiene una relación One-Many propietaria con otro objeto. El otro objeto se almacena en un HashMap. ¿Qué tipo de sincronización solucionaría este problema? Parece suceder en momentos completamente aleatorios y es muy impredecible. Aquí está la excepción que recibo:
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)
Esto no es un problema de sincronización. Esto ocurrirá si la colección subyacente que se está iterando es modificada por cualquier cosa que no sea el iterador mismo.
Iterator it = map.entrySet().iterator();
while (it.hasNext())
{
Entry item = it.next();
map.remove(item.getKey());
}
Esto lanzará una ConcurrentModificationException cuando se llame a it.hasNext () por segunda vez.
El enfoque correcto sería
Iterator it = map.entrySet().iterator();
while (it.hasNext())
{
Entry item = it.next();
it.remove();
}
Suponiendo que este iterador sea compatible con la operación remove ().
Intente utilizar un ConcurrentHashMap en lugar de un HashMap simple
Pruebe CopyOnWriteArrayList o CopyOnWriteArraySet dependiendo de lo que intente hacer.
Quizás otra solución sería adquirir un bloqueo antes de comenzar su modificación / persistencia para no tener otro hilo que modifique lo que está iterando
private ReadWriteLock lock = new ReentrantReadWriteLock();
lock.writeLock().lock();
try{
//itterate and persist
}
finally{
lock.writeLock().unlock();
}
- Si no está haciendo ninguna manipulación, lock.readLock (). Lock () también está bien
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 la adición de una versión a todas las 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 deba ser más alto. Si permite "lecturas sucias", tal vez necesite subir de nivel para ser serializable.