【问题标题】:Concurrent Cache in JavaJava中的并发缓存
【发布时间】:2013-05-10 14:45:34
【问题描述】:

我正在从 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() ?

【问题讨论】:

  • "我正在寻找对以下代码的解释" => 具体哪一部分你不明白?书中给出的解释有哪些部分你不明白? “为什么声明 f = ft;?” => putIfAbsent 如果键不存在于地图中,则返回 null。
  • f.get() 会抛出 NullPointerException 而没有 f = ft

标签: java caching concurrency concurrenthashmap


【解决方案1】:

putIfAbsent 的返回值是现有的,如果已经存在,或者null,如果没有,我们会放入新的。

        f = cache.putIfAbsent(arg, ft);

        if (f == null) {
            f = ft;
            ft.run();
        }

所以if ( f == null ) 的意思是“我们是否将ft 放入缓存中?”。显然,如果我们确实将其放入缓存中,我们现在需要将f 设置为缓存中的那个,即ft

如果我们没有将ft 放入缓存中,那么f 已经是缓存中的那个,因为它是putIfAbsent 返回的值。

【讨论】:

    【解决方案2】:

    因为您正在返回 f.get() 并可能从缓存中删除 f。这允许一段代码适用于所有实例。

        try {
            return f.get();
        } catch (CancellationException e) {
            cache.remove(arg, f);
    

    如果您没有在上面将 f 替换为对 ft 的引用,那么每次 putIfAbsent 返回 null 时都会得到 NPE。

    【讨论】:

      【解决方案3】:

      代码的思路如下。计算某些值的请求来自不同的线程。如果一个线程发起了某个值的计算,其他需要相同结果的线程不应该重复计算,而是应该等待初始计算。计算完成后,结果保存在缓存中。

      这种模式的示例是加载 java 类。如果一个类正在被加载,而另一个线程也请求加载同一个类,它不应该自己加载它,而是等待第一个线程的结果,这样总是不超过一个给定类的实例,加载由同一个类加载器..

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-30
        相关资源
        最近更新 更多