[concurrency-interest] Scalability of ConcurrentHashMap#computeIfAbsent

Benoit Daloze eregontp at gmail.com
Thu Jul 6 10:14:06 EDT 2017


Hello all,

I have been chasing a scalability problem that only happens with over 8
cores on my benchmark and it turns out
ConcurrentHashMap#computeIfAbsent when used as a cache with the same key
does not scale.

Specifically, at least in Oracle JDK 8, #computeIfAbsent on the same key
synchronizes every time (on the same object) to return the existing mapping
value.
On the contrary, ConcurrentHashMap#get() does not synchronize and scales
well.

I thought computeIfAbsent() is a nice method to cache things in a CHM, but
obviously that's a very large drawback.

Original code not scaling:

Charset charset = encodingToCharsetMap.computeIfAbsent(encoding,
EncodingManager::charsetForEncoding);

New code, scaling:

Charset charset = encodingToCharsetMap.get(encoding);
if (charset == null) {
    charset = EncodingManager.charsetForEncoding(encoding);
    encodingToCharsetMap.putIfAbsent(encoding, charset);
    // More complex if charsetForEncoding is not idempotent
}

It seems in general the implementation of computeIfAbsent() in JDK 8
is optimizing for the absent case, which makes little sense when the map is
used as a cache.

Does using a ConcurrentHashMap as a cache with computeIfAbsent() make sense?
Do you think this worth a bug report?

-Benoit
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20170706/0cb8bbaf/attachment.html>


More information about the Concurrency-interest mailing list