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?
> 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
.)
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