Java Concurrency на практике Брайан Гетц (Brian Goetz) представляет пример эффективного масштабируемого кэша для одновременного использования. Окончательная версия примера, показывающая реализацию для класса Memoizer (стр. 108), показывает такой кэш. Мне интересно, почему класс не помечен @ThreadSafe? Клиент, класс Factorizer, кеша правильно помечен @ThreadSafe. В приложении говорится, что если класс не аннотирован ни @ThreadSafe, ни @Immutable, то следует предположить, что он не является потокобезопасным. Тем не менее, Memoizer кажется поточно-ориентированным.
Вот код для Memoizer:
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(e.getCause());
}
}
}
}