2

I have a Map. In order to update the key, I need to check if it already exists. Else, I need to create a new Object and put it.

Map<K,Foo> map = new ConcurrentHashMap<K, Foo>();

My function is this

put(Object value)  {
   if(!map.containsKey(K key)) {
       map.put(key, new Foo());
   } else {
       Foo modifiedFoo = modifyFoo(map.get(key));
       map.put(key, modifiedFoo));
   }
}

I do not want to use synchronization. I am guessing it can probably be transformed into Map<K,AtomicReference<Foo>> map = new ConcurrentHashMap<K, AtomicReference<Foo>>() and furthermore do value.compareAndSet(old, new) where value is type AtomicReference<Foo>. However, two things. How does the case of a non-existing key be handled? And how is the comparison done between the old and new Foo objects?

user592748
  • 1,194
  • 3
  • 21
  • 45

1 Answers1

1

A common pattern in lock-free algorithms is to use an optimistic algorithm wrapped in a retry loop.

insertOrUpdate(key) {
    while(true) {
        var foo = map.get(key);
        if (foo == null) {
            if (map.putIfAbsent(key, new Foo())) break;
        } else {
            if (map.replace(key, foo, modifyFoo(foo))) break;
        }
    }
}

Note that this algorithm doesn't protect against the A-B-A problem, which can in principle be relevant if you allow deletions, depending on your desired semantics in that case.

jkff
  • 17,623
  • 5
  • 53
  • 85