Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the computeIfAbsent() method in ConcurrentHashMap behaving inconsistently?

I have a Java 8 web application running on Apache Tomcat 9. The invocation of ConcurrentHashMap's computeIfAbsent() method is not returning or is taking too long to return.

In the code given below, the line 'Adding to Map' is printed and the line 'Map : ' does not print at all in some cases as if the executing thread is trapped within the method. Once it gets trapped any subsequent calls to the same method with the same id also get stuck and never return while calls with a different id return immediately. Testing on another instance with a different id, the computeIfAbsent() method returned after 2 minutes. The maximum concurrent calls executing the code at the time of testing would be around 20 only. As per my understanding computeIfAbsent() is thread safe. What is wrong here?

private Map<String, Map<String, SomeClass>> aMap = new ConcurrentHashMap<>();
LOGGER.debug("Adding to Map");
Map<String, SomeClass> m = aMap
            .computeIfAbsent(id, k -> Collections.synchronizedMap(new HashMap<>()));
LOGGER.debug("Map : " + m);
like image 471
Nick Avatar asked Jul 16 '19 12:07

Nick


1 Answers

Any subsequent calls to the same method with same id also got stuck and never returned while calls with different id returned immediately ?

Yes, If the computation is in progress any subsequent computation calls of that id will be blocked

If the specified key is not already associated with a value, attempts to compute its value using the given mapping function and enters it into this map unless null. The entire method invocation is performed atomically, so the function is applied at most once per key. Some attempted update operations on this map by other threads may be blocked while computation is in progress so the computation should be short and simple, and must not attempt to update any other mappings of this map.

The maximum concurrent calls executing the code at the time of testing would be around 20 only. As per my understanding ?

No, It completely depends on how many buckets are available in that map

In ConcurrentHashMap, at a time any number of threads can perform retrieval operation but for updation in object, thread must lock the particular segment in which thread want to operate.This type of locking mechanism is known as Segment locking or bucket locking.Hence at a time 16 updation operations can be performed

computeIfAbsent() is thread safe ?

Yes, it is thread safe ConcurrentHashMap

A hash table supporting full concurrency of retrievals and high expected concurrency for updates. This class obeys the same functional specification as Hashtable, and includes versions of methods corresponding to each method of Hashtable. However, even though all operations are thread-safe, retrieval operations do not entail locking, and there is not any support for locking the entire table in a way that prevents all access. This class is fully interoperable with Hashtable in programs that rely on its thread safety but not on its synchronization details.

Honestly i'm not the one who designed and implemented ConcurrentHashMap, but through the internet i found an article for java 8 ConcurrentHashMap improvements, I assume this might causing the delay in first call.

Lazy table initialization that minimizes footprint until first use

like image 119
Deadpool Avatar answered Oct 29 '22 21:10

Deadpool