Производительность ConcurrentHashMap.putIfAbsent - PullRequest
5 голосов
/ 16 апреля 2011

В в своем выступлении об эффективной Java в 54:15 Джошуа Блох рекомендует использовать 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 ]

3 голосов
/ 16 апреля 2011

Я думаю, это потому, что производительность зависит от модели использования. Для карты, где большинство вызовов putIfAbsent будут успешными, тогда защита с помощью get будет медленнее. Для карты, где putIfAbsent часто терпит неудачу, тогда защита с помощью get будет быстрее.

Если вы не выполните оптимизацию для общего случая сбоя, вы можете свободно выбирать, какой метод использовать для вашей карты быстрее.

В примере из видео putIfAbsent обычно не работает, поэтому быстрее защитить его с помощью get.

1 голос
/ 16 апреля 2011

Это добавляет двойную проверку блокировки, семантика транзакции остается прежней;так что это не неправильно .

Является ли это на самом деле оптимизацией, зависит от использования.Мы всегда испытываем искушение проверить в особых случаях, что мы знаем, что существуют более дешевые решения

if A
    cheapSolutionForA();
else
    genericSolution();

Это может сработать или нет - если A редко true, дополнительная проверка обходится дороже, чем экономит.(и когда A действительно иногда имеет значение true, это может нарушить предсказание ветвления ЦП, было бы дешевле всегда использовать универсальное решение, даже когда A = true)

В примере Джошуа, A действительноправда часто.Он должен запрашивать внутреннюю строку для одной и той же строки (одинаковой по значению, а не по идентичности) много раз, поэтому в большинстве вызовов карта уже имеет ключ.

Если каждый вызов intern() получает различную строку, то у карты никогда не будет ключа, и его оптимизационные обратные выстрелы - «оптимизация» стоит больше времени и не экономит ни одного.

ИзКонечно, когда дело доходит до строкового интерна, 1-й случай более реалистичен на практике.

В целом, хотя putIfAbsent() не может предсказать, как он используется, поэтому неразумно включать этот специальный случай "оптимизация" внутриЭто.Во многих случаях использования конкуренция низкая, карта, скорее всего, не имеет ключа при вызове putIfAbsent, в этих случаях было бы неправильно, если встроена «оптимизация».

...