我正在学习Java Concurrency in Practice,但是一些代码使我感到困惑:

private final ConcurrentHashMap<A, Future<V>> cache = new ConcurrentHashMap<A, Future<V>>();

private final Computable<A, V> c;

public Memoizer(Computable<A, V> c) {
    this.c = c;
}

/* (non-Javadoc)
 * @see com.demo.buildingblocks.Computable#compute(java.lang.Object)
 */
@Override
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>() {
                @Override
                public V call() throws Exception {
                    return c.compute(arg);
                }
            };
            FutureTask<V> ft = new FutureTask<V>(eval);
            // what will happen when two threads arrive here at the same time?
            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) {
            launderThrowable(e);
        }
    }
}

我只是不明白,因为putIfAbsent只能保证put操作是原子的,并且如果两个线程都可以输入run方法,它们都返回null。

最佳答案

putIfAbsent不仅在不破坏数据的意义上保证线程安全,而且在它始终可以在数据的最新副本上起作用的意义上,还可以保证线程安全。

同样,如果存在这样的值,它也不会从映射中返回先前的值。因此,第一次调用putIfAbsent将成功,并返回null,因为没有先前的值。第二个调用将一直阻塞,直到第一个调用成功,然后返回映射中的第一个值,从而永远不会调用第二个run()

关于java - 当两个线程同时执行cache.putIfAbsent时会发生什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20171896/

10-12 02:02