ConcurrentMap::compute clarification
Jaromir Hamala
jaromir.hamala at gmail.com
Tue Dec 8 10:12:56 UTC 2015
Hi,
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) {
Objects.requireNonNull(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?
Cheers,
Jaromir
--
“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
More information about the core-libs-dev
mailing list