I know that ConcurentHasMap's compute method is atomic, but does it access the value under the same lock(node lock) every time? So more specifically are the following idioms equivalent regarding to the thread safe access of the map value, in this case Set? Can I fully replace the idiom3 with the idiom1?
ConcurrentHashMap<String, Set<String>> concurrentMap = new ConcurrentHashMap<>();
Object setLock = new Object();
String testValueToAdd = "valueToAdd";
String testValueToRemove = "valueToRemove";
// idiom 1
// adding
concurrentMap.compute("test", (key, setForTheKey) -> {
if(setForTheKey == null) {
setForTheKey = new HashSet<>();
}
setForTheKey.add(testValueToAdd);
return setForTheKey;
});
// removing
concurrentMap.compute("test", (key, setForTheKey) -> {
if(setForTheKey != null) {
setForTheKey.remove(testValueToRemove);
}
return setForTheKey;
});
// idiom 2, concurrent HashSet
// adding
concurrentMap.putIfAbsent("test", ConcurrentHashMap.newKeySet());
concurrentMap.get("test").add(testValueToAdd);
// removing
Set<String> set = concurrentMap.get("test");
if(set != null) {
set.remove(testValueToRemove);
}
// idiom 3, normal Set
// adding
concurrentMap.putIfAbsent("test", new HashSet<>());
Set<String> normalSet = concurrentMap.get("test").
synchronized(setLock) {
normalSet.add(testValueToAdd);
}
// removing
normalSet = concurrentMap.get("test");
if(normalSet!= null){
synchronized(setLock) {
normalSet.remove(testValueToRemove);
}
}
If the following idioms are equivalent, which of them should be preferred? idiom3) manual locking -> error prone idiom2) concurrent hash set is little bit heavy, use locking inside idiom1) should be the same efficiency as idiom3, but without manual locking looks best to me.