是否可以使用putIfAbsent或其任何等价物,如短路操作符。
myConcurrentMap.putIfAbsent(key,calculatedValue)
我希望如果已经有一个calculatedValue,则不应再次计算。 默认情况下,putIfAbsent仍然会每次进行计算,即使它实际上不会再次存储该值。
答案 0 :(得分:1)
Java不允许任何形式的短路保存内置案例,遗憾的是 - 所有方法调用都会导致在控制传递给方法之前完全评估参数。因此,你不能用“普通”语法做到这一点;你需要在Callable
或类似的内部手动包装计算,然后显式调用它。
在这种情况下,我发现很难看出它是如何工作的。 putIfAbsent
基于原子非阻塞操作而工作。如果要做你想做的事情,事件的顺序大致是:
key
(此示例假定它不存在)calculatedValue
(考虑到问题的背景可能很昂贵)如果在步骤2中尚未存在该值,则无法进行非阻塞 - 两个不同的线程同时调用此方法只能在阻塞发生时正确执行。此时,您可以使用synchronized
块,并具有实现的灵活性;你可以用一些简单的锁定来实现你所追求的东西,如下所示:
private final Map<K, V> map = ...;
public void myAdd(K key, Callable<V> valueComputation) {
synchronized(map) {
if (!map.containsKey(key)) {
map.put(key, valueComputation.call());
}
}
}
答案 1 :(得分:1)
您可以将Future<V>
个对象放入地图中。使用putIfAbsent
,只有一个对象,并且通过调用Future.get()
(例如,通过FutureTask
+ Callable
类)来执行最终值的计算。有关使用此技术的讨论,请查看Java Concurrency in Practice。 (示例代码也在SO {。{3}}中。
这样,您的值只计算一次,并且所有线程都获得相同的值。虽然访问值(通过Future.get()
)将阻塞,直到该值由其中一个线程计算,但不会阻止对映射的访问。
答案 2 :(得分:0)
您可以考虑使用Guava ComputingMap
ConcurrentMap<Key, Value> myConcurrentMap = new MapMaker()
.makeComputingMap(
new Function<Key, Value>() {
public Value apply(Key key) {
Value calculatedValue = calculateValue(key);
return calculatedValue;
}
});