ConcurrentHashMap.putIfAbsent的性能

时间:2011-04-16 03:15:28

标签: java concurrenthashmap

his talk about Effective Java 54:15,Joshua Bloch建议在get之前使用putIfAbsent以提高性能和并发性。这引出了一个问题,为什么这个优化已经没有像

那样构建
public V BETTER_putIfAbsent(K key, V value) {
    V result = get(key);
    if (result!=null) return result;
    return ORIGINAL_putIfAbsent(key, value);
}

2 个答案:

答案 0 :(得分:3)

我猜这是因为性能取决于使用模式。对于大多数putIfAbsent调用将成功的地图,然后使用get来保护它将会更慢。对于putIfAbsent经常会失败的地图,然后用get来保护它会更快。

通过不对常见故障情况进行优化,您可以自由选择哪种方法对您的地图更快。

在视频的示例中,putIfAbsent通常会失败,因此使用get来保护它会更快。

答案 1 :(得分:1)

这增加了一个双重检查锁定,事务语义保持不变;所以它没有错误

实际上是否优化取决于使用情况。我们总是试图检查我们知道存在更便宜的解决方案的特殊情况

if A
    cheapSolutionForA();
else
    genericSolution();

这可能有效或无效 - 如果A很少true,则额外支票的费用高于保存费用。 (当A确实有时真的,它可以破坏CPU分支预测,即使A =真,总是使用通用解决方案也可能更便宜)

在约书亚的例子中,A确实经常出现。他必须多次请求相同字符串的实习字符串(值相同,而不是同一性),因此在大多数调用中,地图已经有了密钥。

如果对intern()的每次调用都获得了不同的字符串,那么地图永远不会有密钥,并且他的优化会发生逆火 - “优化”会花费更多时间,并且不会保存。

当然,在字符串实习生方面,第一种情况在实践中更为现实。

一般来说,putIfAbsent()无法预测它的使用方式,因此在其中包含这种特殊情况“优化”是不明智的。在许多用例中,争用率很低,地图很可能在调用putIfAbsent时没有密钥,如果内置“优化”,则在这些情况下会出错。