ConcurrentModificationException y un HashMap

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

Suena menos como un problema de sincronización de Java y más como un problema de locking 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.

Pruebe CopyOnWriteArrayList o CopyOnWriteArraySet dependiendo de lo que intente hacer.

Tenga en cuenta que la respuesta seleccionada no se puede aplicar a su contexto directamente antes de alguna modificación, si está tratando de eliminar algunas entradas del mapa mientras itera el mapa como yo.

Acabo de dar mi ejemplo de trabajo aquí para los novatos para ahorrar su tiempo:

 HashMap map=new HashMap(); //adding some entries to the map ... int threshold; //initialize the threshold ... Iterator it=map.entrySet().iterator(); while(it.hasNext()){ Map.Entry item=(Map.Entry)it.next(); //it.remove() will delete the item from the map if((Integer)item.getValue() 

Quizás otra solución sería adquirir un locking 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