Перемотка в Hashmap

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

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

Bucket (index) = HashMap.indexFor(HashMap.hash(key.hashCode()),
                                  entryArray.length)

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

Когда вы переадресовываете и перемещаете все в новое место (ведро и т.д.), то старые элементы снова перезаписываются и сохраняются в новом ковше в соответствии с их новыми хэш-кодами. Старое пространство, которое было выделено для хранения элементов, - это сбор мусора.

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

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

У меня есть следующие вопросы:

  • Почему связанный список для каждого ведра меняется на переход на новое ведро?
  • Как состояние гонки может привести к бесконечной петле?
  • Как увеличить количество ведер, уменьшающих ожидания поиска время?
  • Элементы, находящиеся в одном ведре, все равно будут вместе ковш после повторного рейса?

Ответ 1

Вот почему мы имеем ConcurrentHashMap. Для подавляющего большинства случаев, когда одна из них не использует одну карту для нескольких потоков без синхронизации, достаточно простого HashMap.

Нет гарантии, что два объекта, которые столкнутся с ведрами n, по-прежнему будут сталкиваться с 2 n ведрами. Просто используя аргумент подсчета, он должен быть примерно наполовину вероятнее, если столкнутся любые два объекта. Меньшее количество столкновений означает более короткие списки, что означает, что время поиска меньше.

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

Ответ 2

  • Детали реализации - я не знаю - возможно, по соображениям производительности.
  • Я не знаю, может ли это привести к бесконечному циклу, но поскольку в HashMap отсутствует синхронизация, он не является потокобезопасным, так или иначе, как он ломается, это не так важно: он будет ломаться так или иначе...
  • В итоге вы получаете меньше предметов за ведро - поэтому поиск предметов в заданном ковше быстрее
  • Нет, это точка перефразирования. Представьте себе простой хэширующий альго index = hash % numberOfBuckets, например.