Структура данных итератора Concurrenthashmap


Мне нужно было спросить о нижеприведенных аспектах ConcurrentHashMap, так как я не могу понять это из исходного кода.
(Пожалуйста, обратите внимание ,что я не спрашиваю о поведении, которое хорошо понятно. Его о механизме, который итератор принимает для отображения поведения)

"The iterator is guaranteed to reflect the state of the map at the time of it's creation."

1.Означает ли это, что итератор получает свою собственную копию резервной карты? Иначе почему бы волатильным считываниям не давать истинного состояния "value", даже после создания итератора? (точное местоположение объекта код будет оценен по достоинству)

2.Как неблокирующему чтению и итерации удается вести себя последовательно, даже когда сегмент подвергается повторному хэшированию?

1 2

1 ответ:

Как упоминалось в комментариях, я не уверен, что поведение ConcurrentHashMap "хорошо понимается". Утверждение, сделанное в вашей неотрицательной цитате, не верно для ConcurrentHashMap.

Итератор для ConcurrentHashMap являетсяслабо согласованным ... государствами документации:

Итераторы, Сплитераторы и перечисления возвращают элементы, отражающие состояние хэш-таблицы в некоторый момент времени или с момента создания итератора/перечисления.

В свет этого,

Краткий ответ на ваш вопрос 1: нет, он не получает свою собственную копию карты

Краткий ответ на ваш вопрос 2: что он не "ведет себя последовательно"


Вот некоторые другие уместные цитаты из javadocs, которые помогают объяснить реализацию:

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

Репликация узлов происходит для каждого сегмента в его методе повторного хэша. Джавадоки для сегмента.метод rehash () объясняет функциональность:

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

Пожалуйста, смотрите превосходную статью Ричарда Бернисона для хорошего обзорного описания деталей реализации ConcurrentHashMap для jdk 7.


Для получения дополнительной информации:

Javadocs для ConcurrentHashMap jdk8

Исходный код для ConcurrentHashMap (openjdk-7)

ConcurrentHashMap возвращает слабо согласованный итератор, почему мы должны использовать его в любом случае?