您的位置:首页 > 编程语言 > Java开发

java并发编程实战-构建高效且可伸缩的结果缓存

2017-07-08 14:41 330 查看
构建高效且可伸缩的结果缓存

1,缓存在服务器应用程序中是一个非常重要的组件。

2,以下讲解一个高效且可伸缩的缓存示例
代码如下

public class CacheSample<IN, OUT> {
/*
* 缓存类容器
* 1,选择线程安全的ConcurrentMap,它提供了并发读写的线程安全,以及“先检查再执行”这样的原子操作putIfAbsent
* 2,选择Future,避免直接存储计算结果值,导致高并发下多个线程同时计算同一个值的情况
*/
private final ConcurrentMap<IN, Future<OUT>> cache = new ConcurrentHashMap<IN, Future<OUT>>();

public OUT doSomething(final IN arg) throws InterruptedException {
while (true) {
Future<OUT> f = cache.get(arg);
if (f == null) {
// 如果没有IN对应的Future,则创建Future
Callable<OUT> eval = new Callable<OUT>() {
public OUT call() throws InterruptedException {
return doing(arg);
}
};
FutureTask<OUT> ft = new FutureTask<OUT>(eval);
// 通过putIfAbsent完成“先检查再添加”的原子操作
// putIfAbsent如果已存在则返回已存在的值,如果不存在则添加新建的Future并返回null
f = cache.putIfAbsent(arg, ft);
if (f == null) {
// 如果新添加进缓存,则启动计算
f = ft;
ft.run();
}
}
try {
// 不管f是新创建的还是通过缓存中获取的,如果Future还没计算结束就阻塞,如果计算结束就获取值
return f.get();
} catch (CancellationException e) {
// 当某个计算被取消或者失败,需要从缓存中移除该IN及对应的Future
// 否则,将持续性获取不到正确的值,但同时又无法再进行新的计算(缓存污染)
cache.remove(arg, f);
} catch (ExecutionException e) {
throw LaunderThrowable.launderThrowable(e.getCause());
}
}
}

private OUT doing(final IN arg){
// 非常耗时的处理过程................
return null;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: