4 ответов:
в ответе @dotsid он говорит следующее:
если вы измените хэш-карту каким-либо образом, то ваш код просто сломан.
он является правильным. Хэш-карта, которая обновляется без синхронизации, сломается даже если потоки используют непересекающиеся наборы ключей. Вот некоторые из вещей, которые могут пойти не так.
если один поток делает
put, тогда другой поток может увидеть устаревшее значение для хэш-карты размер.когда поток делает
putкоторый запускает перестройку таблицы, другой поток может видеть временные или устаревшие версии ссылки на массив hashtable, его размер, его содержимое или хэш-цепочки. Может возникнуть хаос.когда поток делает
putдля ключа, который сталкивается с некоторым ключом, используемым некоторым другим потоком, и последний поток делаетputдля его ключа, то последний может увидеть устаревшую копию хэш-цепи ссылка. Может возникнуть хаос.когда один поток зондирует таблицу ключом, который сталкивается с одним из ключей другого потока, он может столкнуться с этим ключом в цепочке. Он вызовет equals на этом ключе, и если потоки не синхронизированы, метод equals может столкнуться с устаревшим состоянием в этом ключе.
и если у вас есть два потока одновременно делать
putилиremoveзапросы, есть множество возможностей для гонки условия.я могу придумать три решения:
- использовать
ConcurrentHashMap.- использовать обычный
HashMapно синхронизировать снаружи; например, используя примитивные мьютексы,Lockобъекты, и так далее.- использовать другой
HashMapдля каждого потока. Если потоки действительно имеют непересекающийся набор ключей, то не должно быть необходимости (с алгоритмической точки зрения) для них совместно использовать одну карту. Действительно, если ваши алгоритмы включают потоки повторение ключей, значений или записей карты в какой-то момент, разделение одной карты на несколько карт может дать значительное ускорение для этой части обработки.
просто используйте ConcurrentHashMap. ConcurrentHashMap использует несколько блокировок, которые охватывают диапазон хэш-ведер, чтобы уменьшить вероятность оспаривания блокировки. Существует незначительное влияние на производительность для получения бесспорной блокировки.
чтобы ответить на ваш первоначальный вопрос: согласно javadoc, пока структура карты не меняется, вы в порядке. Это означает полное отсутствие удаления элементов и добавления новых ключей, которых еще нет на карте. Замена значения связанные с существующими ключами-это нормально.
Если многократные потоки получают доступ к карте хеша одновременно, и по крайней мере один из потоков изменяет карту структурно, это должно синхронизироваться внешне. (Структурная модификация - это любая операция, которая добавляет или удаляет одно или несколько сопоставлений; простое изменение значения, связанного с ключом, который уже содержит экземпляр, не является структурной модификацией.)
хотя это не дает никаких гарантий по поводу видимости. Так вы должны быть готовы принять извлечение устаревших ассоциаций иногда.
это зависит от того, что вы имеете в виду под "доступ". Если вы просто читаете, вы можете читать даже те же ключи, пока видимость данных гарантируется в разделе"происходит-перед" правила. Это значит, что
HashMapне должно меняться, и все изменения( начальные конструкции) должны быть завершены до того, как любой читатель начнет доступHashMap.если вы измените a
HashMapв любом случае, тогда ваш код просто сломан. @Stephen C дает очень хорошее объяснение почему.EDIT: если первый случай-это ваша фактическая ситуация, я рекомендую вам использовать
Collections.unmodifiableMap()чтобы быть уверенным, что ваш HashMap никогда не меняется. Объекты, на которые указываетHashMapне должно меняться также, так агрессивно используяfinalключевое слово может помочь вам.и как говорит @Lars Andren,
ConcurrentHashMapсамый лучший выбор в большинстве случаев.
изменение хэш-карты без надлежащей синхронизации из двух потоков может легко привести к состоянию гонки.
- Когда a
put()приводит к изменению размера внутренней таблицы, это занимает некоторое время, а другой поток продолжает записывать в старую таблицу.- два
put()для разных ключей приводят к обновлению одного и того же ведра, если хэш-коды ключей равны по модулю размера таблицы. (На самом деле, связь между хэш-кодом и индексом ведра сложнее, но столкновения все равно могут произойти.)
Comments