В ConcurrentHashMap
на самом деле красно-черное дерево (для большого количества элементов) или связанный список (для небольшого количества элементов) используется при столкновении (то есть два разных ключа имеют одинаковый хэш-код),Но вы правы, когда говорите, что связанный список (или красно-черное дерево) может расти бесконечно (при условии, что у вас бесконечная память и размер кучи).
Основная идея HashMap
или ConcurrentHashMap
то есть вы хотите получить значение на основе его ключа в O (1) сложности времени.Но в действительности коллизии случаются, и когда это происходит, мы помещаем узлы в дерево, связанное с сегментом (или ячейкой массива).Таким образом, Java может создать HashMap
, где размер массива останется фиксированным, и перефразирование никогда не произойдет, но если они это сделают, все значения ключей должны быть размещены в массиве фиксированного размера (вместе с их связанными деревьями).
Допустим, у вас есть такой тип HashMap
, где размер вашего массива фиксирован и равен 16, а в него добавлено 1000 пар ключ-значение.В этом случае вы можете иметь не более 16 различных хеш-кодов.Это, в свою очередь, означает, что у вас будут коллизии во всех (1000-16) put
с, и эти новые узлы окажутся в дереве, и их больше нельзя будет выбрать за O (1) по времени.В дереве вам понадобится O (log n) время для поиска ключей.
Чтобы этого не произошло, HashMap
использует вычисление коэффициента загрузки, чтобы определить, какая часть массива заполнена парами ключ-значение.Если он заполнен на 75% (настройки по умолчанию), любой новый put
создаст новый массив большего размера, скопирует в него существующее содержимое и, таким образом, получит больше сегментов памяти или пространства хэш-кода.Это гарантирует, что в большинстве случаев коллизии не произойдут, и дерево не потребуется, и вы получите большинство ключей за O (1) раз.