Let's consider the following following code:
ConcurrentHashMap<String, Set<String>> map = new ConcurrentHashMap<>();
// Add element: {mapKey, setValue}
map.computeIfAbsent(mapKey, new Function<String, Set<String>>() {
@Override
public Set<String> apply(String mapK) {
return ConcurrentHashMap.newKeySet();
}
}).add(setValue);
// Remove element: {mapKey, setValue}
Set<String> updatedSet = map.computeIfPresent(mapKey, new BiFunction<String, Set<String>, Set<String>>() {
@Override
public Set<String> apply(String mapK, Set<String> old) {
old.remove(setValue);
return old;
}
});
// I need remove mapKey, but I cannod do this like this, because of race condition bug
if (updatedSet.isEmpty()) {
map.remove(mapKey);
}
So, what we can see:
ConcurrentHashMap<String, Set<String>>
map, where key
of map is String
, and value
is ConcurrentHashSet
.set
, which is value of map
, when set
is empty
.set
, because of race condition bug.Is there any brilliant solution of my problem?
computeIfPresent
removes the entry if the mapper returns null
. Instead of performing the removal in a separate step, return null
from the mapper if you want to remove the entry.
(Also, you should really fold the .add(setValue)
into your computeIfAbsent
mapper, and use compute
instead of computeIfAbsent
, because you're not doing anything to protect the add
call right now. Using merge
would also be an option.)