Your code is thread-safe, but there is a possibility that the function will be called multiple times for the same value.
For example this race condition:
//thread 1
V v = map.get(key);
if (v == null) {
// thread 2 comes in
{
V v = map.get(key);
if (v == null) {
return map.putIfAbsent(key, function.apply(key));
} else {
return v;
}
}
// thread 1 continues
return map.putIfAbsent(key, function.apply(key));
} else {
return v;
}
In this case, both thread1 and thread2 will execute function.apply(key)
, but the putIfAbsent
will make sure only the first value is used. If you use put
instead of putIfAbsent
with this race condition, the last value will be used.
If you use computeIfAbsent
with this race condition, only the first value will be used, but function.apply(key)
will not even be executed the second time.
BTW, your benchmark is not really representative.
- You allways use different keys, so the case where the same key is used is not tested.
- The benchmark is single-threaded as far as I can see, so all locks will be skipped.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…