许多人阅读了“ 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是幂等的:如果将来可能更改结果,则缓存结果是没有意义的。

07-24 09:33