Java 在Brian Goetz的并发性实践中,为什么在可伸缩缓存的最后一个示例中有一段时间(正确)?
在Brian Goetz的《实践中的并发》一书的代码清单5.19中,他展示了他完成的线程安全记忆器类 我想我理解了这个例子中的代码,只是我不理解Java 在Brian Goetz的并发性实践中,为什么在可伸缩缓存的最后一个示例中有一段时间(正确)?,java,multithreading,concurrency,Java,Multithreading,Concurrency,在Brian Goetz的《实践中的并发》一书的代码清单5.19中,他展示了他完成的线程安全记忆器类 我想我理解了这个例子中的代码,只是我不理解 while ( true ) 是在比赛开始的时候 public V compute(final A arg) throws InterruptedException 方法 为什么代码需要while循环 下面是完整的代码示例 public class Memoizer<A, V> implements Computable<A, V
while ( true )
是在比赛开始的时候
public V compute(final A arg) throws InterruptedException
方法
为什么代码需要while循环
下面是完整的代码示例
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());
}
}
}
}
公共类备忘录生成器实现可计算{
私有最终ConcurrentMap缓存
=新的ConcurrentHashMap();
私有最终可计算c;
公共记忆器(可计算c){this.c=c;}
public V compute(最后一个参数)抛出InterruptedException{
while(true){
Future f=cache.get(arg);
如果(f==null){
Callable eval=新的Callable(){
public V call()抛出InterruptedException{
返回c.compute(arg);
}
};
FutureTask ft=新的FutureTask(eval);
f=缓存.putIfAbsent(arg,ft);
如果(f==null){f=ft;ft.run();}
}
试一试{
返回f.get();
}捕获(取消异常e){
cache.remove(arg,f);
}捕获(执行例外){
扔掉可清洗的垃圾(如getCause());
}
}
}
}
代码的主要目标似乎是计算任何类型的A。看来while(true)
唯一有效的方法就是取消。如果存在取消,则该方法将重试计算
基本上,
while(true)
将确保(除ExecutionException之外)在某一点上,函数将完成并正确计算,即使是取消操作。在取消异常时进行永久循环重试。如果引发任何其他异常,则将停止执行
Biotext.org在同一问题上也有自己的见解。当我第一次读到这篇文章时,同样的东西打动了我。我想我已经报告了,但没有得到回复。是的,也许这本书需要更明确地说明解决方案的这个特性(取消时重试)。是的。我很清楚,我已经重新阅读了它。非常感谢您提供的优秀链接。但是在示例中,FutureTask从未被取消。你能帮我理解代码路径是如何执行的吗?FutureTask正在创建并添加到缓存中。其他进程可以从缓存中获取任务并取消它。假设书中列表中的代码已完成,则不可能这样做。缓存被封装。因此,我对所提供代码中CancellationException的实际来源感到困惑(尽管我仍然理解并接受您关于while循环的意图和目的的原始答案,但我同意Japley对在本例中包含它的担忧。)c.compute可能会抛出未经检查的CancellationException。可计算性的实现可能更加复杂;e、 g.使用未来任务本身;并合理地抛出CancellationException。从我对Doug Lea的Java并发编程的模糊记忆中,这种异常通常应该传播。回忆录代码是通用的;对于给定的示例,这永远不会发生。但是,如果要在另一个上下文中重复使用Memoizer,那么处理CancellationException是合理的。