许多人阅读了“ Java Concurrency in Practice”,但为了方便起见将代码粘贴到此处。
5.19备忘录的最终实现:
public class Memoizer<A, V> implements Computable<A, V> {
private final ConcurrentMap<A, Future<V>> cache = new ConcurrentHashMap<A, Future<V>>();
private final Computable<A, V> c;
public Memoizer(Computable<A, V> c) {
this.c = c;
}
public V compute(final A arg) throws InterruptedException {
while (true) {
Future<V> f = cache.get(arg);
if (f == null) {
Callable<V> eval = new Callable<V>() {
public V call() throws InterruptedException {
return c.compute(arg);
}
};
FutureTask<V> ft = new FutureTask<V>(eval);
f = cache.putIfAbsent(arg, ft);
if (f == null) {
f = ft;
ft.run();
}
}
try {
return f.get();
} catch (CancellationException e) {
cache.remove(arg, f);
} catch (ExecutionException e) {
throw LaunderThrowable.launderThrowable(e.getCause());
}
}
}
}
我的问题是在catch(ExecutionException e)中,应添加以下代码段:
cache.remove(arg, f);
正确?
最佳答案
如果compute
是幂等的,则将其从缓存中删除将导致不必要的计算,因为下一次调用compute
的结果也将是ExecutionException
。
如果将f
保留在缓存中,则下一个调用将再次运行f.get()
,该调用将立即以ExecutionException
返回,而无需实际执行计算。
因此,它看起来更有效。
请注意,人们希望compute
是幂等的:如果将来可能更改结果,则缓存结果是没有意义的。