I'm trying to find an answer to these, but not able to understand(or confirm) it on Google or in Java docs.
My implementation looks like as this:
Map<String, POJO> map = new ConcurrentHashMap<String, POJO>();
if I do
value1 = map.get(key1);
value1.setProp(prop);
Any other thread may override.
Now, I'm thinking if I do like follows: would it be an atomic operation/in another words, it will block the key1 segment?
map.compute(key1, (key1, value1) -> { value1.setProp(prop) });
Javadoc for compute
function
Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping). The entire method invocation is performed atomically. Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this Map.
References:
1.https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html 2.https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#compute-K-java.util.function.BiFunction-
EDIT:
for my final implementation, I did something like this as all threads share NewMap and at the end, I new list of POJOs
Abstract Data Type
public class NewMap {
private Map<String, POJO> map;
private boolean isUpdatable;
void NewMap(){
isUpdatable = true;
map = new ConcurrentHashMap();
}
void putPOJOProp1(String key, Type value) throws ReadOnlyException{
map.compute(key, (k,v) -> {
if(!isUpdatable) throw new ReadOnlyException();
if(k == null){
POJO p = new POJO();
p.setProp1(value);
v = p;
} else {
v = v.setProp1(v)
}
});
}
void putPOJOProp2....
void putPOJOProp3....
List<POJO> getAll() {
isUpdatable = false;
List<POJO> pojos;
for(key: map.getKeys()) {
Pojo p = map.get(key);
p.setKey(key);
pojos.add(p);
}
return pojos;
}
}
The Javadoc for ConcurrentHashMap.compute states
The entire method invocation is performed atomically.
Note, by comparison the ConcurrentSkipListMap.compute
is NOT atomic.
A more compact form of Alexey Soshin's answer is
Map<String, long[]> map = new ConcurrentSkipListMap<>();
map.put("A", new long[2]);
IntStream.range(0, 1_000_000)
.parallel()
.forEach(i -> map.compute("A", (k, v) -> {
v[0]++;
v[1]++;
return v;
}));
System.out.println(Arrays.toString(map.get("A")));
prints something like
[643553, 597254]
c.f. HashMap produces something like
[244786, 245993]
However, use a ConcurrentHashMap
and you get the expected
[1000000, 1000000]