我正在从Brian Goetz的并发书籍中寻找对以下代码的解释。
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());
}
}
}另外,在putIfAbsent()调用之后,为什么语句f = ft;而不是直接做ft.run()呢?
发布于 2013-05-10 23:28:46
如果已经存在,则putIfAbsent的返回值是现有的;如果没有,则返回null,然后将新的返回值放入其中。
f = cache.putIfAbsent(arg, ft);
if (f == null) {
f = ft;
ft.run();
}所以if ( f == null )的意思是“我们把ft放到缓存里了吗?”显然,如果我们将其放入缓存,我们现在需要将f设置为缓存中的值,即ft。
如果我们没有将ft放到缓存中,那么f已经是缓存中的值了,因为它是putIfAbsent返回的值。
发布于 2013-05-10 22:49:49
因为您将返回f.get()并可能从缓存中删除f。这允许一段代码适用于所有实例。
try {
return f.get();
} catch (CancellationException e) {
cache.remove(arg, f);如果你没有在上面用对ft的引用替换f,那么每次putIfAbsent返回null时,你都会得到一个NPE。
发布于 2013-05-11 00:47:24
代码的思想如下所示。计算某些值的请求来自不同的线程。如果一个线程已经启动了某个值的计算,其他需要相同结果的线程不应该重复计算,而应该等待初始计算。当计算完成时,结果被保存在缓存中。
这种模式的例子是java类的加载。如果一个类正在被加载,而另一个线程也请求加载相同的类,那么它不应该自己加载它,而是等待第一个线程的结果,以便始终只有一个给定类的实例,由相同的类加载器加载。
https://stackoverflow.com/questions/16484939
复制相似问题