3

This refers to an accepted solution to the a question raised in this thread

public void insertOrReplace(String key, String value) {
    for (;;) {
        String oldValue = concurrentMap.putIfAbsent(key, value);
        if (oldValue == null)
            return;

        final String newValue = recalculateNewValue(oldValue, value);
        if (concurrentMap.replace(key, oldValue, newValue))
            return;
    }
}

I would love to thoroughly understand the code.

I believe putIfAbsent and replace altogether can be considered as a compound operation. Is this compound operation atomic without explicit synchronization on object oldValue? Or just because of the for loop, it guarantees the atomicity? What exactly does the loop do? Would it cause an infinite loop that makes the method never end?

Community
  • 1
  • 1
Aaron Li
  • 103
  • 2
  • 9

1 Answers1

0

First of all, the original question introduces somewhat bizarre code. Not sure what it is good for but lets leave that aside.

Second thing, the chosen answer and the one that you copy-pasted here is just a different way to do the same code as in the question.

So, what does this (bizarre) method do:

  1. Checks if the key is mapped to a value and if not assigns the value and exists.
  2. If it was, recalculate the value and replace the old value.

Why do we need the loop then? Cause if 2 threads are recalculating the value and do the replace "together", only 1 is going to be successful and hence return from the method. The "loosing" thread will need to go thru the process again. Probably will get a new value in the putIfAbsent call and will recalculate a new value to be replaced, this time might be OK.

A few things to note:

  1. I would recommend reading carefully the APIs of ConcurrentMap's putIfAbsent and replace methods.
  2. There is a corner case (that will never happen in reality) that a call to this method will be stuck forever cause it will always "loose" to another call.
  3. I suspect that synchronizing this whole method will be better avoiding this whole cumbersome loopings. But since I am not fully aware of what this code aims to resolve I can not officially claim that.
shlomi33
  • 1,458
  • 8
  • 9
  • why it is guaranteed out of 2 concurrent threads there must be a loosing one? Would it be possible both of them win? Meaning both of them got same oldVal hence can be replaced with the new one? – Aaron Li Sep 08 '14 at 12:12
  • No. Please read the concurrentMap.replace(key, oldValue, newValue) Javadoc and see that it will only replace the 'oldValue' if the 'key' is actually mapped to it. If 2 find the same oldValue only 1 will succeed. – shlomi33 Sep 08 '14 at 12:30
  • I looked into the source code of replace method. Apparently it is synchronized with a lock where at one time only one thread can access to it. Therefore, out of 2 threads, once the winning thread succeeded the loosing thread will not be able to do replacing as the oldVal has been already changed by the winning thread. In this case the loosing thread will have to wait until the next loop. – Aaron Li Sep 09 '14 at 07:44