[concurrency-interest] A bug in JDK 8 ConcurrentMap::compute?

Jaromir Hamala jaromir.hamala at gmail.com
Wed Dec 9 05:22:53 EST 2015


I apologize if this is not the right group to discuss possible issues in
JDK8 j.u.c package. Please feel free to point me to a more appropriate

I stumbled upon an interesting issue with default implementation of
`compute(K key, BiFunction<? super K, ? super V, ? extends V>
remappingFunction)` in JDK8 `ConcurrentMap`.
According to its contract the default method implementation assumes map
implementations do not support null values.

This is the begin of the default implementation:

default V compute(K key, BiFunction<? super K, ? super V, ? extends V>
remappingFunction) {
        V oldValue = get(key);
        for(;;) {
            V newValue = remappingFunction.apply(key, oldValue);
            if (newValue == null) {
                // delete mapping
                if (oldValue != null || containsKey(key)) {
                    // something to remove
                    if (remove(key, oldValue)) {

Let's say we have an empty map and 2 threads:
T1 is calling the `compute('foo', someFunction)`
T2 is concurrently calling calling `put('foo', 'bar');`

so the T1 will get `oldValue = null`, but `containsKey()` will return
`true` - because T2 already created the mapping `foo -> bar`. Hence T1 will
call `remove('foo', null)` !

Contract of `remove()` says: `throws NullPointerException if the specified
key or value is null, and this map does not permit null keys or values
optional.` -> the T1 will throw NPE.
Is it a bug in default method impl or do I understand it wrong?


“Perfection is achieved, not when there is nothing more to add, but when
there is nothing left to take away.”
Antoine de Saint Exupéry
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20151209/3d1e0860/attachment.html>

More information about the Concurrency-interest mailing list