Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to lock on key in a ConcurrentHashMap

I am caching an object, which is created by a thread, into a map. The creation of the object is expensive, so I don't want multiple threads running to create the object because the put() hasn't returned. Once a thread tries to create an object for that key, other threads shouldn't try to create the object, even if put is not yet complete. Will using computeIfAbsent() work to acquire a 'lock' on that particular key? If not, is there another way to achieve this?

like image 759
dt94 Avatar asked Aug 06 '18 22:08

dt94


1 Answers

> Will using computeIfAbsent() work to acquire a 'lock' on that particular key?

Yes; per the Javadoc for ConcurrentHashMap.computeIfAbsent(...):

The entire method invocation is performed atomically, so the function is applied at most once per key.

That's really the whole point of the method.

However, to be clear, the lock is not completely specific to that one key; rather, ConcurrentHashMap typically works by splitting the map into multiple segments, and having one lock per segment. This allows a great deal of concurrency, and is usually the most efficient approach; but you should be aware that it means that some threads might block on your object creation even if they're not actually touching the same key.

If this is a problem for you, then another approach is to use something like ConcurrentHashMap<K, AtomicReference<V>> to decouple adding the map entry from populating the map entry. (AtomicReference<V> doesn't have a computeIfAbsent method, but at that point you can just use normal double-checked locking with a combination of get() and synchronized.)

like image 137
ruakh Avatar answered Sep 23 '22 00:09

ruakh