views:

5254

answers:

5

I am persisting objects using JPA. The Main object has an owning One-Many relationship with another object. The other object is stored in a HashMap. What sort of synchronization would fix this problem? It seems to happen at completely random times and is very unpredictable. Here is the exception I get:

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)
A: 

Simple; use:

synchronized (myHashMap) {
  for(Element e : myHashMap) {
  ...
  }
}
Dani
I'm not the one iterating over the HashMap though... Hibernate is.
Grasper
Basically, it iterates over your object, which means that you can either lock it when you're giving it to hibernate, or when you do your adds and puts. Alternatively, you can try Collections.synchronizedMap (see http://java.sun.com/j2se/1.4.2/docs/api/java/util/HashMap.html)
Dani
A: 

It sounds less like a Java synchronization issue and more like a database locking problem.

I don't know if adding a version to all your persistent classes will sort it out, but that's one way that Hibernate can provide exclusive access to rows in a table.

Could be that isolation level needs to be higher. If you allow "dirty reads", maybe you need to bump up to serializable.

duffymo
HashMap is thread-safe. Its not sunchronization issue.
TBH
Did you down vote me? Did you not read my answer? I said it was a database locking problem, not "synchronization". Your reading skills are as poor as your spelling.
duffymo
+14  A: 

This is not a synchronization problem. This will occur if the underlying collection that is being iterated over is modified by anything other than the Iterator itself.

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

This will throw a ConcurrentModificationException when the it.hasNext() is called the second time.

The correct approach would be

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

Assuming this iterator supports the remove() operation.

Robin
Possibly, but it looks as if Hibernate is doing the iterating, which should be implemented reasonably correctly. There could be callback modifying the map, but that is unlikely. The unpredictability points to an actual concurrency problem.
Tom Hawtin - tackline
This exception has nothing to do with threading concurrency, it is caused by the backing store of the iterator being modified. Whether by another thread of not doesn't matter to the iterator. IMHO it is a poorly named exception since it gives an incorrect impression of the cause.
Robin
I agree however that if it is unpredictable, there is most likely a threading issue which is causing the conditions for this exception to occur. Which makes it all the more confusing because of the exception name.
Robin
A: 

Try either CopyOnWriteArrayList or CopyOnWriteArraySet depending on what you are trying to do.

Javamann
+4  A: 

Try using a ConcurrentHashMap instead of a plain HashMap

Chochos
Did that really solve the problem? I am experiencing the same issue but I can most certainly rule out any threading issues.
tob
Another solution is to create a copy of the map and iterate through that copy instead. Or copy the set of keys and iterate through them, getting the value for each key from the original map.
Chochos
It is Hibernate who is iterating through the collection so you cannot simply copy it.
tob