5

54:15のEffectiveJavaに関する彼の講演で、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);
}
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は、確かに頻繁に真実です。彼は何度も同じ文字列(同じ値で、IDではない)のインターン文字列を要求している必要があります。したがって、ほとんどの呼び出しで、マップにはすでにキーがあります。

のすべての呼び出しintern()が異なる文字列を取得する場合、マップにキーが含まれることはなく、彼の最適化は裏目に出ます。「最適化」にはより多くの時間がかかり、何も節約されません。

もちろん、ストリングインターンに関しては、最初のケースの方が実際にはより現実的です。

ただし、一般的に、putIfAbsent()それがどのように使用されているかを予測することはできないため、この特殊なケースの「最適化」をその中に含めることは賢明ではありません。多くのユースケースでは、競合は少なく、呼び出されたときにマップにキーがない可能性がありますputIfAbsent。これらの場合、「最適化」が組み込まれていると間違っています。

于 2011-04-16T05:07:20.067 に答える