The iterators returned by the iterator method of the collections 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.
Similarly, Iterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration. They do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.
Mike Cheung wrote:
http://docs.oracle.com/javase/7/docs/api/java/util/LinkedHashMap.html
The iterators returned by the iterator method of the collections 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.
This means if I have an Iterator going through the LinkedHashMap, I'll get a ConcurrentModificationException if the map is changed (ie insert or remove a key). But does it happen even if I wrap it with Collections.synchronizedMap() like this which is also shown on the page?
Mike Cheung wrote:Again, this sounds like it will have issues if an Iterator is going through the ConcurrentHashMap, if the map is changed (ie insert or remove a key), except I wouldn't be getting a ConcurrentModificationException. What would be the behavior in this case?
Also what does it mean by "iterators are designed to be used by only one thread at a time"? How can it be a concurrent map if I can't do concurrent read from multiple threads?
"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here
The line marked *** will be a structural alteration whether you are single‑threaded or multithreaded, and will cause an Exception in the next line, so you never reach the second structural alteration.add element → map
map ← add element
add element → map
map ← add element
new Iterator
iterate → map
map ← add element ***
iterate → map
map ← remove element
Winston Gutkowski wrote:
Also what does it mean by "iterators are designed to be used by only one thread at a time"? How can it be a concurrent map if I can't do concurrent read from multiple threads?
Not with the same Iterator, no.
Testing ConcurrentHashMap
two
one
three
Testing Synchronized LinkedHashMap
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(Unknown Source)
at java.util.LinkedHashMap$KeyIterator.next(Unknown Source)
at threadandsynchronization.CHMTest.main(CHMTest.java:38)
Winston Gutkowski wrote:Well, the docs also say: "Retrievals reflect the results of the most recently completed update operations holding upon their onset."
This is sometimes referred to as "weakly consistent" in that it will return the logically "next" key/value/entry based on the current state of the Map at the time the method is actioned. I suspect also (although it's not explicitly stated, and TBH, I'm not sure) that it means it could possibly throw NoSuchElementException if there is no "next" element to be had.
Winston Gutkowski wrote:
Also what does it mean by "iterators are designed to be used by only one thread at a time"? How can it be a concurrent map if I can't do concurrent read from multiple threads?
Not with the same Iterator, no.
Winston
Henry Wong wrote:
Agreed. It isn't common for multiple threads to share one iterator -- if you want to do some sort of producer / consumer setup, it is better to use some sort of collection that has methods that returns elements in an order, like a thread safe queue.
Henry
Heena Agarwal wrote:The iterator returned by ConcurrentHashMap is a screenshot of the map at a particular time. It may reflect some of those changes that happened after you created the iterator but there is no guarantee. I think the state changes that take place after you start iterating are never reflected. But these are implementation details. As such we know that iterating through a ConcurrentHashMap may not give us the most recent updates that happened to the Map ( the ones that happened after we created the iterator ). We would use it if we either don't care about missing some of the updates or if we know that such updates are not likely and we want maximum concurrency in that kind of a setting.
Heena wrote:It may reflect some of those changes that happened after you created the iterator but there is no guarantee. I think the state changes that take place after you start iterating are never reflected. But these are implementation details. As such we know that iterating through a ConcurrentHashMap may not give us the most recent updates that happened to the Map ( the ones that happened after we created the iterator ). We would use it if we either don't care about missing some of the updates or if we know that such updates are not likely and we want maximum concurrency in that kind of a setting.
This isn't the case with the iterator returned by a LinkedHashMap or a synchronized view of a LinkedHashMap.
Consider Paul's rocket mass heater. |