Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does java.util.concurrent.ConcurrentHashMap.putIfAbsent need to be in a syncronized block?

I am trying to track down a race condition and all signs seem to be pointing to ConcurrentHashMap.putIfAbsent(). Is it possible that if 2 threads call putIfAbsent() on an empty map with the same key that both could do their lookup to see that the key does not exist yet so both threads then try to add it? For some reason when I first started using putIfAbsent() I did not think the call would need to be synchronized. But now I can't see how it would prevent both threads from adding their values if the timing was right. I have not been able to reproduce this outside of production.

Thanks

like image 730
Brian Avatar asked Dec 16 '22 07:12

Brian


1 Answers

None of the operations for any concurrent collection needs to use synchronized.

This is by design and in fact locking the collection has no effect on other operations. (Unless they are locked as well) In which case it will make them slower.

Is it possible that if 2 threads call putIfAbsent() on an empty map with the same key that both could do their lookup to see that the key does not exist yet so both threads then try to add it?

Both can try, but only one will succeed. It is not possible for two threads to appear to have succeeded.

For some reason when I first started using putIfAbsent() I did not think the call would need to be synchronized.

It doesn't.

But now I can't see how it would prevent both threads from adding their values if the timing was right.

It performs a CAS operation in the code which means only one operation can succeed and the thread will know which one. A CAS operation doesn't need locking as it uses the underlying assembly instruction to perform this. In fact you would normally implement a lock using a CAS operation, rather than the other way around.

like image 168
Peter Lawrey Avatar answered Dec 17 '22 20:12

Peter Lawrey