I have a multi-process situation which I need help understanding how the Java engine works. One process will be polling another system for information and generating and maintaining a collection of active objects (probably in a HashMap). At any time new objects (HashMap Entries) may be added and/or old objects deleted. Simultaneously, another process will be iterating across these objects, using them as a basis to perform work (probably using an Iterator). I expect the main loop will awake, initialize an iterator, and then work down the list of objects. Now, how much of this is handled by Java itself, and what needs to be synchronized? Will the iterator's list be updated as HashMap entries are added and removed? Do I have to check for the (continued) existence of each object at each iter.next() call? Will the thing crash if iter.next() refers to a (recently) removed entry? Is there some other approach that I should be using? Thanks In Advance... Jim!
you are not allowed to change a collection (add or remove) when you iterate over it. this will cause an error and unpredictable result. check the API , it clearly says that while iterating over a collection YOU need to check that the collection doesnt change. so you will need to synchornize the iteration as well as the parts that access the collection you have.
But Randy, that's the problem - he does want to iterate over the collection while it's being modified. The ConcurrentModificationException is great for debugging purposes in that it helps identify the cause of problems - but it's not something we'd want to see in most finished applications. Roy's advice works - if you synchonrize over the whole iteration in addition to the individual method calls, you're safe. The individual methods can be synchronized using Collections.synchronizedMap(), but that doesn't protect the iteration. You must sync that part explicitly. Alternately, if the iteration is a lengthy process, it may well be desireable to allow other threads to put/get/remove while you're iterating. This can be accomplished by making a copy of the HashMap entries, and iterating over that rather than the original HashMap. You'll miss any objects added to the map after the copying - but you'll probably want to be re-running the iterator periodically anyway, so those objects will be picked up on the next time through the iterator. And the iterator may have some objects that have been removed from the map by the time you get around to processing them - if this is a problem, do a (synchronized) containsKey() just before processing the item, to see if it's still there. There's still a chance it could be removed immediately afterwards, and you could still end up processing an object after it's been removed. Depending on your application this could be a serious problem, or just a minor inefficiency. You can put in some more synchronization to avoid this. As long as you're exiting and rentering the sync block for each new iteration, other threads will have an opportunity to modify the map in between. Which is the whole point of this method - you want the other threads to not be completely blocked during the iteration.
Jim is quite correct. In fact, that is the way that JavaBean objects handle event notification. Since it is possible that a listener can try to add itself to the event notification vector while the bean is iterating through the Vector to notify listeners of an event, the bean copies the Vector and then iterates through the copy. Here's an example of some code I used in a bean I developed many years ago: