ConcurrentModificationException e um HashMap

Eu estou usando objects persistentes usando JPA. O object Principal possui um relacionamento One-Many com outro object. O outro object é armazenado em um HashMap. Que tipo de synchronization resolveria esse problema? Parece acontecer em tempos completamente randoms e é muito imprevisível. Aqui está a exceção que recebo:

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) 

Este não é um problema de synchronization. Isso ocorrerá se a coleção subjacente que está sendo iterada for modificada por algo diferente do próprio iterador.

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

Isso lançará um ConcurrentModificationException quando o it.hasNext () é chamado na segunda vez.

A abordagem correta seria

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

Assumindo que este iterador suporta a operação remove ().

Tente usar um ConcurrentHashMap em vez de um simples HashMap

Soa menos como um problema de synchronization Java e mais como um problema de bloqueio de database.

Eu não sei se adicionar uma versão a todas as classs persistentes irá resolvê-la, mas é uma maneira que o Hibernate pode fornecer access exclusivo a linhas em uma tabela.

Pode ser que o nível de isolamento precise ser maior. Se você permitir “leituras sujas”, talvez precise ser serializado.

Tente CopyOnWriteArrayList ou CopyOnWriteArraySet dependendo do que você está tentando fazer.

Observe que a resposta selecionada não pode ser aplicada ao seu contexto diretamente antes de alguma modificação, se você estiver tentando remover algumas inputs do mapa enquanto iterar o mapa como eu.

Eu apenas dou meu exemplo de trabalho aqui para iniciantes economizarem seu tempo:

 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() 

Talvez outra solução seria adquirir um bloqueio antes de iniciar sua modificação / persistência, a fim de não ter algum outro segmento modificar o que você está iterando

 private ReadWriteLock lock = new ReentrantReadWriteLock(); lock.writeLock().lock(); try{ //itterate and persist } finally{ lock.writeLock().unlock(); } 
  • Se você não estiver fazendo nenhuma manipulação, talvez lock.readLock (). Lock () também esteja OK