Concurrent structures and collections in Java 5
Iterating over ConcurrentHashMap
On the previous page, we gave an example of ConcurrentHashMap, using one to store a record of count-per-query on a web server.
Arguably, each count will be "in and-out", and one might argue that the improvement in throughput
over a regular synchronized hash map won't be so great, since contention won't generally be so high.
An additional benefit of ConcurrentHashMap is that we can
iterate over the map without locking. (Indeed, it is not actually possible to lock a ConcurrentHashMap
during this or any other operation.)
Recall that with an ordinary HashMap– even one wrapped in a
Collections.synchronizedMap(...) wrapper!– iteration over the map must occur
whilst synchronized on the map in order to be thread-safe. If, due to incorrect synchronization,
one thread does update the map whilst another is iterating over it, one of the threads is
liable to throw a ConcurrentModificationException.
In contrast, whilst one or more threads is iterating over a ConcurrntHashMap,
other threads can concurrently access the map. Such operations will never throw
a ConcurrentModificationException. In this case, the thread that is iterating over the map
is not guaranteed to "see" updates since the iteration began, but it will still see the map in
a "safe state", reflecting at the very least the state of the map at the time iteration began.
This is both good news and bad news:
- Good news: it is perfect for cases where we want iteration not to affect concurrency, at the expense
of possibly missing an update while iterating (e.g. in our imaginary web server,
while iterating in order to persist the current query counts to a
database: we probably wouldn't care about missing the odd count);
- Bad news: because there's no way to completely lock a ConcurrentHashMap, there's
no easy option for taking a "snapshot" of the map as a truly atomic operation.
Other concurent structures
On the next page, we'll look at two so-called copy-on-write structures
added in Java 5: CopyOnWriteArrayList and CopyOnWriteArraySet. These provide high read concurrency by making an entirely new copy
every time the collection is updated.