Experiencing weird behavior of ConcurrentHashMap
: at first the map gets modified concurrently by several threads using compare-and-set operations like putIfAbsent()
and remove()
. After some time (tens of seconds or even a minute) another thread checks if the map is empty or not using two methods:
myMap.isEmpty()
methodmyMap.entrySet().iterator().hasNext()
Surprisingly these two methods give different results. isEmpty()
returns true
and iterator.hasNext()
returns true
right after that. The calls are performed without any pause in between and no write operations are performed on the map at this time.
Please note, that according to logs there are no situations when isEmpty()
returns false
and iterator.hasNext()
returns false
at the same time. So it is always isEmpty()
method not 'seeing' any entries in the map.
Wonder if this is expected behavior of ConcurrentHashMap
.
Documentation states that:
Bear in mind that the results of aggregate status methods including size, isEmpty, and containsValue are typically useful only when a map is not undergoing concurrent updates in other threads. Otherwise the results of these methods reflect transient states that may be adequate for monitoring or estimation purposes, but not for program control.
That gives the idea that methods like size()
and isEmpty()
are expected to return values consistent with actual contents of the map when there are no ongoing write operations.
The get() method of ConcurrentHashMap class returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
ConcurrentHashMap class is thread-safe i.e. multiple threads can operate on a single object without any complications. At a time any number of threads are applicable for a read operation without locking the ConcurrentHashMap object which is not there in HashMap.
Creates a new, empty map with a default initial capacity (16), load factor (0.75) and concurrencyLevel (16).
The javadoc for ConcurrentHashMap.getEntrySet()
tells you that the iterator you obtain from the set is weakly consistent.
Javadoc for the java.util.concurrent
package explains what "weakly consistent" means:
... their Iterators and Spliterators provide weakly consistent rather than fast-fail traversal:
- they may proceed concurrently with other operations
- they will never throw ConcurrentModificationException
- they are guaranteed to traverse elements as they existed upon construction exactly once, and may (but are not guaranteed to) reflect any modifications subsequent to construction.
That last bullet is the important one. It tells you that the iterator is a view of what was in the map at the moment when the iterator was created. The contents of the iterator won't change if you subsequently change the contents of the map.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With