Параметры конструктора ConcurrentHashMap?

Меня интересуют параметры для построения ConcurrentHashMap:

  • initialCapacity по умолчанию равно 16 (понятно).
  • loadFactor по умолчанию равно 0,75.
  • concurrencyLevel по умолчанию равно 16.

Мои вопросы:

  • Какие критерии следует использовать для увеличения или уменьшения loadFactor?
  • Как установить количество одновременно обновляющихся потоков?
  • Какие критерии следует использовать для увеличения или уменьшения concurrencyLevel?

Кроме того:

  • Каковы признаки хорошей реализации хэш-кода? (Если вопрос SO касается этого, просто дайте ссылку на него.)

Спасибо!


person non sequitor    schedule 15.10.2009    source источник
comment
Спасибо, Дэйв, гораздо лучше, я возьму свою очередь у тебя.   -  person non sequitor    schedule 15.10.2009


Ответы (4)


Краткий ответ: установите «начальную емкость» примерно на то, сколько сопоставлений вы ожидаете разместить на карте, и оставьте другие параметры по умолчанию.

Длинный ответ:

  • коэффициент загрузки — это соотношение между количеством «бакетов» в карте и количеством ожидаемых элементов;

  • 0,75 обычно является разумным компромиссом — насколько я помню, это означает, что при хорошей хеш-функции в среднем мы ожидаем около 1,6 перенаправлений, чтобы найти элемент на карте (или около этой цифры);

    • изменение коэффициента загрузки меняет компромисс между большим количеством перенаправлений для поиска элемента и меньшим количеством потраченного впустую пространства — 0,75 обычно является хорошим значением;

    • в принципе, установите ConcurrencyLevel на количество одновременных потоков, которые вы ожидаете изменить карту, хотя переоценка этого значения, похоже, не имеет плохого эффекта, кроме пустой траты памяти (я немного написал на производительность ConcurrentHashMap некоторое время назад, если вам интересно)

Неформально ваша хеш-функция должна быть нацелена на максимально возможную «случайность» в битах. Или, точнее, хеш-код для данного элемента должен давать каждому биту примерно 50%-ную вероятность быть установленным. На самом деле проще проиллюстрировать это на примере: опять же, вам могут быть интересны некоторые вещи, о которых я писал как работает строковая хеш-функция и соответствующие рекомендации по хеш-функциям. Отзывы, безусловно, приветствуются по любому из этих материалов.

Одна вещь, которую я также упоминаю в какой-то момент, заключается в том, что на практике вам не нужно быть слишком параноиком: если ваша хэш-функция создает «разумную» степень случайности в некоторых битах, тогда она будет часто быть в порядке. В худшем случае вставка репрезентативных фрагментов данных в строку и получение хэш-кода строки на самом деле не так уж плохо работают.

person Neil Coffey    schedule 15.10.2009

Коэффициент загрузки в первую очередь связан с качеством хэш-функции. Чем ближе к нулю коэффициент загрузки, тем меньше вероятность коллизий, даже если хеш-функция не так велика. Компромисс заключается в том, что объем памяти больше. Другими словами, HashMap не распределяет записи по отдельным корзинам для каждого отдельного хэш-кода, а группирует их по близости, поэтому чем больше у нее корзин, тем шире распределение, тем меньше вероятность коллизий.

Таким образом, суть в том, что вы возитесь с коэффициентом загрузки, чтобы улучшить время поиска или уменьшить объем памяти в соответствии с вашими потребностями и объектами, которые вы храните на карте.

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

Качественная реализация хеш-кода обеспечивает как можно более широкое распределение потенциальных значений объекта с наименьшим количеством коллизий при соблюдении условий контракта. Другими словами, это позволяет HashMap (или Set, в зависимости от обстоятельств) распределять объекты по отдельным корзинам, что ускоряет поиск.

person Yishai    schedule 15.10.2009

loadFactor: контролирует, когда реализация решает изменить размер хеш-таблицы. Слишком высокое значение приведет к пустой трате места; слишком низкое значение приведет к дорогостоящим операциям изменения размера.

concurrencyLevel: указывает реализации попытаться оптимизировать заданное количество потоков записи. Согласно документам API, отключение в 10 раз не должно сильно влиять на производительность.

Допустимый параллелизм между операциями обновления определяется необязательным аргументом конструктора concurrencyLevel (по умолчанию 16), который используется в качестве подсказки для внутреннего изменения размера. Таблица внутренне разделена, чтобы разрешить указанное количество одновременных обновлений без конфликтов. Поскольку размещение в хеш-таблицах по существу случайное, фактический параллелизм будет отличаться. В идеале вы должны выбрать значение, соответствующее максимальному количеству потоков, которые когда-либо будут одновременно изменять таблицу. Использование значительно более высокого значения, чем вам нужно, может привести к пустой трате места и времени, а значительно более низкое значение может привести к конфликту между потоками. Но завышенные и заниженные оценки в пределах порядка величины обычно не оказывают большого заметного влияния.

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

person Jim Garrison    schedule 15.10.2009

По умолчанию для loadFactor установлено значение 0,75, какие критерии следует использовать для увеличения или уменьшения этого значения?

Вам нужно немного узнать, как работают хеш-карты, прежде чем вы сможете понять, как это работает. Карта, по сути, представляет собой серию ведер. Каждое значение на карте помещается в корзину в зависимости от его хэш-кода. LoadFactor означает, что если корзины заполнены более чем на 75%, необходимо изменить размер карты.

concurrencyLevel по умолчанию установлен на 16, как мы можем установить количество одновременно обновляемых потоков? Какие критерии следует использовать, чтобы скорректировать это в большую или меньшую сторону?

Это вопрос о том, сколько потоков вы ожидаете для одновременного (одновременного) изменения карты.

Хэш-коды см. в Эффективная Java

person Kevin    schedule 15.10.2009