[concurrency-interest] ConcurrentMap.replace

Doug Lea dl@cs.oswego.edu
Mon, 24 Nov 2003 20:22:27 -0500

> I can see how this replace method is the same as putIfPresent(K key, V
> value, V expectedValue), but how would this method work for the case
> where I don't care what the current value is, but I want to replace it
> only if containsKey(key) is true? (e.g. I want to atomically replace
> it regardless of its current value with my NullObject without the side
> effect of adding the key it if it's been removed)?

The bad news is that I still have a hard time thinking of a compelling
use case where you'd want putIfPresent() but not replace(). And I
worry about the slippery-slope problem here. For example, maybe you
would like even better:
  boolean putIf(K key, Predicate<V> predicate, C value)
supplying a callback function that the map appliess to get(key); that
could for example here return true if its argumentis non-null.  But as
a matter of policy, we don't support callbacks in these kinds of
classes because doing callbacks inside our internal sync schemes would
make it impossible to provide guarantees about it working.

The good news is that the new replace() method is a "universal"
construction that allows you do do any of these things yourself,
although not quite as efficiently as if each were built in.  For
example, you can write yourself:

boolean putIfPresent(ConcurrentMap m, K key, V value) {
  for (;;) {
     V old = m.get(key);
     if (old == null) return false;  // *
     if (m.replace(key, old, value)) return true;

This is basically equivalent to a classic compareAndSet (CAS) loop. 
As with CAS, it will loop only if contended, i.e., hardly ever in
most applications.

You could replace line (*) with any predicate, thus getting
the effect of the above nonexistent predicate version.

Can you live with this?