Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/359.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Brian Goetz的并发性实践中,为什么在可伸缩缓存的最后一个示例中有一段时间(正确)?_Java_Multithreading_Concurrency - Fatal编程技术网

Java 在Brian Goetz的并发性实践中,为什么在可伸缩缓存的最后一个示例中有一段时间(正确)?

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

在Brian Goetz的《实践中的并发》一书的代码清单5.19中,他展示了他完成的线程安全记忆器类

我想我理解了这个例子中的代码,只是我不理解

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是合理的。