2009-03-02 60 views
94

我正在使用持久對象使用JPA。主對象與另一個對象擁有擁有一對多關係。另一個對象存儲在一個HashMap中。什麼樣的同步可以解決這個問題?它似乎發生在完全隨機的時間,並且非常不可預測。這裏是我得到的例外:ConcurrentModificationException和一個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

你能否提供一些更多的合作NTEXT?你在合併,更新或刪除一個實體嗎?這個實體有什麼關聯?你的級聯設置如何? – ordnungswidrig 2009-03-03 11:52:20

+0

從堆棧跟蹤中,您可以看到異常發生在迭代HashMap時。當然其他線程正在修改地圖,但異常發生在迭代的線程中。 – Chochos 2010-08-31 14:43:32

+0

可能的重複[迭代通過集合,避免ConcurrentModificationException在循環中刪除時](http://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re) – Raedwald 2016-03-28 14:31:32

回答

205

這不是同步問題。如果正在迭代的底層集合被Iterator本身以外的其他任何東西修改,就會發生這種情況。

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

這會在第二次調用it.hasNext()時拋出ConcurrentModificationException。

正確的做法將是

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

假設此迭代器支持remove()操作。

3

這聽起來不像Java同步問題,更像是數據庫鎖定問題。

我不知道是否向所有的持久化類添加一個版本會對它進行排序,但這是Hibernate可以獨佔訪問表中的行的一種方式。

可能是隔離級別需要更高。如果你允許「髒讀」,也許你需要碰到可序列化。

+0

HashMap是線程-安全。它不是sunchronization問題。 – TBH 2010-02-02 20:07:13

1

嘗試CopyOnWriteArrayList或CopyOnWriteArraySet,具體取決於您嘗試執行的操作。

51

嘗試使用的ConcurrentHashMap,而不是一個簡單的HashMap

-1

的也許另一個解決方案是爲了不具有其他線程修改您的迭代什麼開始您的修改/持久之前獲得鎖

private ReadWriteLock lock = new ReentrantReadWriteLock(); 
lock.writeLock().lock(); 
try{ 
//itterate and persist 
} 
finally{ 
lock.writeLock().unlock(); 
    } 
  • 如果你沒有做任何操作也許lock.readLock()鎖()也行
相關問題