我正在学习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/