2009-03-02 12 views
94

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:ConcurrentModificationException y un HashMap

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) 
+1

¿Puede dar un poco más co ntext? ¿Se está fusionando, actualizando o eliminando una entidad? ¿Qué asociaciones tiene esta entidad? ¿Qué hay de tus configuraciones en cascada? – ordnungswidrig

+0

Desde el seguimiento de pila, puede ver que la Excepción ocurre al iterar a través del HashMap. Seguramente algún otro hilo está modificando el mapa, pero la excepción ocurre en el hilo que se está iterando. – Chochos

+0

duplicado Posible de [Iterar a través de una colección, evitando ConcurrentModificationException al retirar en bucle] (http://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re) – Raedwald

Respuesta

205

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á un ConcurrentModificationException cuando el it.hasNext() se llama la segunda vez.

El enfoque correcto sería

Iterator it = map.entrySet().iterator(); 
    while (it.hasNext()) 
    { 
     Entry item = it.next(); 
     it.remove(); 
    } 

Suponiendo que esta iterador apoya la operación de eliminación().

+1

Posiblemente, pero parece que Hibernate está haciendo la iteración, que debería implementarse de manera razonablemente correcta. Podría haber una devolución de llamada modificando el mapa, pero eso es poco probable. La imprevisibilidad apunta a un problema de concurrencia real. –

+0

Esta excepción no tiene nada que ver con la concurrencia de subprocesos, es causada por el almacén de respaldo del iterador que se está modificando. Ya sea por otro hilo de no no le importa al iterador. En mi humilde opinión es una excepción mal nombrada ya que da una impresión incorrecta de la causa. – Robin

+0

Sin embargo, estoy de acuerdo en que, si es impredecible, lo más probable es que sea un problema de subprocesamiento que esté causando las condiciones para que se produzca esta excepción. Lo que lo hace aún más confuso debido al nombre de la excepción. – Robin

3

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 sus clases persistentes lo arregla, pero eso es una manera de que Hibernate puede proporcionar un acceso exclusivo a las filas de una tabla.

Podría ser que el nivel de aislamiento tiene que ser mayor. Si permite "lecturas sucias", tal vez necesite subir de nivel para ser serializable.

+0

HashMap es hilo -seguro. No es un problema de suncronización. – TBH

+1

¿Me votaste? ¿No leíste mi respuesta? Dije que era un problema de bloqueo de la base de datos, no una "sincronización". Sus habilidades de lectura son tan pobres como su ortografía. – duffymo

+1

@TBH ¿Cómo es HashMap seguro para subprocesos? –

1

intente cualquiera CopyOnWriteArrayList o CopyOnWriteArraySet dependiendo de lo que está tratando de hacer.

51

Intente utilizar un ConcurrentHashMap en lugar de un HashMap llanura

+0

¿Eso realmente resolvió el problema? Estoy experimentando el mismo problema, pero puedo descartar cualquier problema de enhebrado. – tobiasbayer

+2

Otra solución es crear una copia del mapa e iterar a través de esa copia. O copie el conjunto de claves e itere a través de ellas, obteniendo el valor de cada clave del mapa original. – Chochos

+0

Hibernate está iterando en la colección, por lo que no puede simplemente copiarla. – tobiasbayer

-1

Quizás otra solución sería la de obtener un bloqueo antes de iniciar su modificación/persistencia con el fin de no tener algún otro hilo modificar lo que su están produce la iteración

private ReadWriteLock lock = new ReentrantReadWriteLock(); 
lock.writeLock().lock(); 
try{ 
//itterate and persist 
} 
finally{ 
lock.writeLock().unlock(); 
    } 
  • Si usted no está haciendo ningún tipo de manipulación tal lock.readLock(). bloqueo() también está bien
Cuestiones relacionadas