Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConcurrentHashMap contains values, but size() method returns 0

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:

  1. calling myMap.isEmpty() method
  2. trying to see if there are any entries in iterator: myMap.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.

like image 843
Oleg Mozzhechkov Avatar asked Mar 21 '16 10:03

Oleg Mozzhechkov


People also ask

How do I get value from ConcurrentHashMap?

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.

What is the use of ConcurrentHashMap () in multithreading?

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.

What is default size of ConcurrentHashMap?

Creates a new, empty map with a default initial capacity (16), load factor (0.75) and concurrencyLevel (16).


1 Answers

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.

like image 78
Solomon Slow Avatar answered Oct 07 '22 20:10

Solomon Slow