Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java ConcurrentHashMap.computeIfPresent value modification visibility

Let's say I have a concurrent map with collections as value:

Map<Integer, List<Integer> map = new ConcurrentHashMap<>();
map.putIfAbsent(8, new ArrayList<>());

and I update the value as follows:

map.computeIfPresent(8, (i, c) -> {
    c.add(5);
    return c;
});

I know that computeIfPresent entire method invocation is performed atomically. However, considering this map is accessed by multiple threads concurrently, I'm a little bit concerned about data visibility of the modifications done to the underlying collection. In this case will the value 5 be seen in the list after calling map.get

My question is will change to the list be visible in other threads upon calling map.get if changes are performed within computeIfPresent method call.

Please note that I am aware that changes to the list will not be visible if I were to take reference to the list before doing the update operation. I am unsure if the changes to the list will be visible if I take reference to the list (by calling map.get) after the update operation.

I am unsure how to interpret the docs, but it seems to me that happens-before relationship will guarantee visibility of the changes to the underlying collection in this particular case

More formally, an update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key reporting the updated value

like image 961
Marin Veršić Avatar asked Sep 30 '18 11:09

Marin Veršić


Video Answer


1 Answers

The fact that that method is documented to be atomic, does not mean much about visibility (unless that is part of the documentation). For example to make this simpler:

// some shared data
private List<Integer> list = new ArrayList<>();

public synchronized void addToList(List<Integer> x){
     list.addAll(x);
}

public /* no synchronized */ List<Integer> getList(){
     return list;
}

We can say that addToList is indeed atomic, only one thread at a time can call it. But once a certain thread calls getList - there is simply no guarantee about visibility (because for that to be established, it has to happens on the same lock ). So visibility is something happens before is concerned with and computeIfPresent documentation does not say anything about that, at all.

Instead the class documentation says:

Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove).

The key point here is obviously overlap, so some other threads calling get (thus getting a hold of that List), can see that List in some state; not necessarily a state where computeIfPresent started (before you actually called get). Be sure to read further to understand what that some actually might mean.

And now to the trickiest part of that documentation:

Retrievals reflect the results of the most recently completed update operations holding upon their onset. More formally, an update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key reporting the updated value.

Read that sentence about completed again, what it says is that the only thing you can read when a thread does get is the last completed state that List was in. And now the next sentence says that there is a happens before established between two actions.

Think about it, a happens-before is established between two subsequent actions (like in the synchronized example above); so internally when you update a Key there could be a volatile written signaling that update has finished (I am pretty sure it's not done this way, just an example). For the happens before to actually work, get has to read that volatile and see the state that was written to it; if it sees that state it means that happens before has been established; and I guess that by some other technique this is actually enforced.

So to answer your question, all the threads calling get will see the last completed action that happened on that key; in your case if you can guarantee that order, I'd say, yes, they will be visible.

like image 89
Eugene Avatar answered Sep 30 '22 17:09

Eugene