Back to concurrency. By now it is clear that for the double checked locking
to work the variable needs to be declared as volatile
. But then what if double checked locking is used as below.
class Test<A, B> {
private final Map<A, B> map = new HashMap<>();
public B fetch(A key, Function<A, B> loader) {
B value = map.get(key);
if (value == null) {
synchronized (this) {
value = map.get(key);
if (value == null) {
value = loader.apply(key);
map.put(key, value);
}
}
}
return value;
}
}
Why does it really have to be a ConcurrentHashMap and not a regular HashMap? All map modification is done within the synchronized
block and the code doesn't use iterators so technically there should be no "concurrent modification" problems.
Please avoid suggesting the use of putIfAbsent
/computeIfAbsent
as I am asking about the concept and not the use of API :) unless using this API contributes to HashMap
vs ConcurrentHashMap
subject.
Update 2016-12-30
This question was answered by a comment below by Holger "HashMap.get
doesn’t modify the structure, but your invocation of put
does. Since there is an invocation of get
outside of the synchronized block, it can see an incomplete state of a put
operation happening concurrently." Thanks!