• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 436
  • Last Modified:

Why is the HashMap iterator intermittently failing?

There are times when I start my program and it runs fine and then other times when it spits out this error:

Exception in thread "Thread-3" java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextEntry(HashMap.java:806)
	at java.util.HashMap$EntryIterator.next(HashMap.java:847)
	at java.util.HashMap$EntryIterator.next(HashMap.java:845)
	at domain.EntityManager$UpdateLoop.updateContent(EntityManager.java:130)
	at domain.EntityManager$UpdateLoop.run(EntityManager.java:111)
	at java.lang.Thread.run(Thread.java:722)

Open in new window


What could be causing this? This is the only code that is iterating the HashMap:

            for (Map.Entry<String, Entity> entry : entities.entrySet()) {
                String key = entry.getKey();
                Entity item = entry.getValue();
                if (item.isDestroyed()){
                    entities.remove(key);
                    ViewManager.getInstance().removeItem(key);
                    //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
                } else {
                    item.update(1);
                    ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
                    ViewManager.getInstance().updateItem(ci);                    
                }
                item.update(1);
            }

Open in new window


And then there are a couple methods earlier that populate the HashMap:

    public void initialize(String side, int ships, int charges, double speed) throws InvalidDataException {
        for (int i=0; i < ships; i++) {                                   
            cs = new CargoShip(side, charges, speed);       
            entities.put(cs.getIdentifier(), cs);            
        }
    }
    
    public void initializeClouds(int clouds, int duration, double size) throws InvalidDataException {
        for (int i=0; i < clouds; i++) {                                   
            dc = new DebrisCloud(duration, size);       
            entities.put(dc.getIdentifier(), dc);            
        }        
    }

Open in new window




0
Eindoofus
Asked:
Eindoofus
  • 5
1 Solution
 
for_yanCommented:
The API descriptiion has some afdvice for this case:
http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html


Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be "wrapped" using the Collections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map:

   Map m = Collections.synchronizedMap(new HashMap(...));

The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
0
 
for_yanCommented:


T think this has relevant information over how you iterate the HashMap:
http://stackoverflow.com/questions/1066589/java-iterate-through-hashmap
0
 
for_yanCommented:


In particular read this remark in the above link:
One caveat: if you want to remove items mid-iteration, you'll need to do so via an Iterator (see karim79's answer). However, changing item values is OK (see Map.Entry).
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
EindoofusAuthor Commented:
Thanks :). How could I change the following code to work with that synchronized feature?

private HashMap<String, Entity> entities = new HashMap<String, Entity>();

Open in new window


And also what import statements do I need to use for it to work?
0
 
for_yanCommented:
I think their suggestion is to create the hashMap in this way:

 Map m = Collections.synchronizedMap(new HashMap(...));

In this stackoverflow link they suggest to change the way you iterate and use
explicit iterator, as you are removing the entries, just as they mentioned


0
 
for_yanCommented:
Maybe another way is to use old-style Hashtable ?

I would also think about removing entries outside of iteration loop - I'd mark them, say make a list of them  and remove directly
outside of iteration process.
Well, no one suggests it, but it kind of seems safer to me - not very well understand how it happens iteration with simulatneous removal
of entries over which iteration is going.

But I would rather be trying all these options starting with the simplest - say change the way of iteration to explicit iterator
as those folks in stackoverflow suggest.
0

Featured Post

[Webinar On Demand] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now