[concurrency-interest] Scalability of ConcurrentHashMap#computeIfAbsent

Benoit Daloze eregontp at gmail.com
Thu Jul 6 11:25:40 EDT 2017


Thank you for your answers, I'll give it a shot on JDK9.

As Jonas points out, I want to optimize for the key-is-present case.
I believe checking eagerly if the key is in the map does not affect
semantics, but it might affect the performance of the absent case a tiny
bit.

Another workaround which would work just as well here:

Charset charset = encodingToCharsetMap.get(encoding);
if (charset == null) {
    charset = encodingToCharsetMap.computeIfAbsent(encoding,
EncodingManager::charsetForEncoding);
}

So essentially just adding a fast-path, because #computeIfAbsent does not
scale on the same key when the key is already in the map.

-Benoit

On Thu, Jul 6, 2017 at 5:01 PM, Josh Humphries <jhump at bluegosling.com>
wrote:

> On Thu, Jul 6, 2017 at 10:47 AM, Doug Lea <dl at cs.oswego.edu> wrote:
>
>> On 07/06/2017 10:14 AM, Benoit Daloze wrote:
>>
>> > 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.
>>
>
> This is necessary since the spec
> <https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#computeIfAbsent-K-java.util.function.Function-> indicates
> that the operation (including computation of the value) is atomic. To make
> this atomic, it must use pessimistic locking, so it seems you are observing
> lock contention. (Interestingly, this behavior contrasts with the default
> implementation
> <https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentMap.html#computeIfAbsent-K-java.util.function.Function-> in
> the ConcurrentMap interface, which uses optimistic concurrency and
> retries and makes no promise of atomicity.) The scalability of the map
> relies on many threads operating on different keys, not all operations
> using the same key.
>
> Your work-around, to have every thread eagerly execute the function in
> parallel and then "first one wins" to store the value in the map, looks
> appropriate.
>
>
>>
>> Please try this using JDK9, which locks only on (possible) hash
>> collision. (See discussion in list archives.)
>>
>
> The original question indicates the operation not scaling is for the same
> key, so I think it will encounter a hash collision and the same scalability
> issue even with this patch.
>
>
>> If we had known that JDK9 would face so much adoption delay,
>> we might have tried to arrange backports of this and other minor
>> improvements and fixes...
>>
>> -Doug
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> Concurrency-interest at cs.oswego.edu
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>
>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20170706/45fce197/attachment-0001.html>


More information about the Concurrency-interest mailing list