HashMap в Java

Эта реализация коллекции обеспечивает постоянную производительность для основных операций (получение (get) и размещение (put)), предполагая, что хэш-функция правильно распределяет элементы по сегментам. Итерация по представлениям коллекций требует времени, пропорционального "емкости" экземпляра HashMap (количеству сегментов) плюс его размеру (количеству сопоставлений "ключ-значение"). Таким образом, очень важно не устанавливать слишком высокую начальную емкость (или слишком низкий коэффициент загрузки), если важна производительность итераций.

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

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

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

Обратите внимание, что эта реализация не синхронизирована. Если несколько потоков обращаются к хэш-мап одновременно, и хотя бы один из потоков структурно модифицирует карту, она должна быть синхронизирована извне. (Структурная модификация - это любая операция, которая добавляет или удаляет одно или несколько сопоставлений; простое изменение значения, связанного с ключом, который уже содержится в экземпляре, не является структурной модификацией.) Обычно это выполняется путем синхронизации на некотором объекте, который естественным образом инкапсулирует карту. Если такого объекта не существует, карту следует "обернуть" с помощью метода Collections.synchronizedMap. Лучше всего это делать во время создания, чтобы предотвратить случайный несинхронизированный доступ к карте:

Map m = Collections.synchronizedMap(new HashMap(...));

Итераторы, возвращаемые всеми "методами представления коллекции" этого класса, работают без сбоев: если карта структурно изменена в любое время после создания итератора, любым способом, кроме собственного метода удаления итератора, итератор выдаст исключение ConcurrentModificationException. Таким образом, перед лицом одновременной модификации итератор быстро и чисто выходит из строя, вместо того, чтобы подвергать риску произвольное недетерминированное поведение в неопределенное время в будущем.

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


Читайте также:


Комментарии

Популярные сообщения из этого блога

Методы класса Object в Java

Как получить текущий timestamp в Java

Основные опции JVM для повышения производительности и отладки