构建高效且可伸缩的结果缓存
2017-08-20 本文已影响19人
zlcook
-
使用ConcurrentMap而不使用HashMap可以提高并发性,即避免下面问题:
-
使用HashMap需要对整个compute加锁,synchronized
并发性降低
-
-
缓存Map中存放Future而不使用最终的结果,可以避免同一个key被计算多次情况。如下:
- 使用ConcurrentMap接口的putIfAbsent方法(“先检查再执行”的原子性操作)而不是put,可以避免重复计算问题,如下:
package net.jcip.examples;
import java.util.concurrent.*;
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(); //将会调用c.compute(arg)
}
}
try {
return f.get();
} catch (CancellationException e) {
cache.remove(arg, f);
} catch (ExecutionException e) {
throw LaunderThrowable.launderThrowable(e.getCause());
}
}
}
}