The single-check idiom can be used to implement a thread safe-lazy init with (compared to the double-check) the possible drawback of wasting some computation time by multiple concurrent inits. It is
Single-check idiom
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) {
field = result = computeFieldValue();
}
return result;
}
Here, we need the volatile field
to avoid that a partially initialized object is passed to another thread, that is - the assignment (write) implicitly performs the necessary synchronization.
I would like to implement a parametrized lazy init cache, which is essentially represented by a Map<Integer, Object>
, where each element is created using lazy init.
My question is: is it enough to use a ConcurrentHashMap
to avoid the issue with partial initialization. That is, in that case the thread-safe implementation of a lazy-init cache using the single-check idiom can be given by
private final ConcurrentHashMap<Integer, ItemType> items = new ConcurrentHashMap<Integer, ItemType>();
ItemType getItem(Integer index) {
ItemType result = items.get(index);
if (result == null) {
result = computeItemValue(index);
items.put(index, result);
}
return result;
}
In other words: I assume that 'items.put(index, result)' performs the necessary synchronization (since it is a write). Note that the question might be twofold here: first I wonder if this works in the (a) current JVM implementation, second (more importantly) I wonder if this is guaranteed (given the documentation/contract) of ConcurrentHashMap
.
Note: Here I assume that computeItemValue generates an immutable object and guarantees thread safety in the sense of the single-check idiom (that is, once object construction is completed, the object returned behaves identically for all threads). I assume this is item 71 in J. Bloch's book.