5

Joshua Bloch在54:15关于 Effective Java的演讲中建议使用getbeforeputIfAbsent以提高性能和并发性。这让我想到了为什么这种优化还没有内置的问题

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

2 回答 2

3

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

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

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

于 2011-04-16T04:59:48.640 回答
1

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

是否真的是优化取决于使用情况。我们总是很想检查我们知道存在更便宜的解决方案的特殊情况

if A
    cheapSolutionForA();
else
    genericSolution();

这可能有效,也可能无效 - 如果A很少true,额外检查的成本超过它节省的成本。(当 A 有时确实为真时,它可能会破坏 CPU 分支预测,即使 A=true 也总是使用通用解决方案可能会更便宜)

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

如果每次调用都intern()得到一个不同的字符串,那么地图永远不会有密钥,他的优化会适得其反——“优化”会花费更多时间,但不会节省任何时间。

当然,当涉及到字符串实习生时,第一种情况在实践中更为现实。

但总的来说,putIfAbsent()无法预测它是如何使用的,因此在其中包含这种特殊情况“优化”是不明智的。在许多用例中,争用很低,调用时映射很可能没有键putIfAbsent,如果内置“优化”,在这些情况下将是错误的。

于 2011-04-16T05:07:20.067 回答