Live coding puzzles question 176 of 180 senior
Write a thread-safe lazily initialised cache where each key is computed once.
synchronizedaround aHashMaplookup and compute- Correct:
ConcurrentHashMapwithcomputeIfAbsent, or with aFutureTaskvalue when the computation is slow enough that holding the bin lock is unacceptable Collections.synchronizedMapplus a double check- A
ThreadLocalcache per thread
computeIfAbsent is the one-liner and the right first answer:
V get(K key) {
return cache.computeIfAbsent(key, this::compute);
}
Exactly one thread computes, the others wait, no duplicate work. Then volunteer the caveat, because it
is what the question is for: the function runs while the bin is locked, so a slow or recursive
computation blocks other writers to that bin or throws IllegalStateException.
The classic alternative from Java Concurrency in Practice keeps the lock short by storing a future:
Future<V> future = cache.get(key);
if (future == null) {
FutureTask<V> task = new FutureTask<>(() -> compute(key));
future = cache.putIfAbsent(key, task);
if (future == null) {
future = task;
task.run(); // compute outside any map lock
}
}
return future.get();
Mention cache eviction and the failure case too: a failed computation must be removed, or you have cached an exception forever.