Ответ - да, есть потенциальные условия гонки:
- при изменение размера HashMap двумя потоками одновременно
- при случается столкновение .Столкновение может произойти, когда два элемента отображаются на одну и ту же ячейку, даже если они имеют разные хэш-коды.Во время разрешения конфликта может быть условие гонки, и одна добавленная пара ключ / значение может быть перезаписана другой парой, вставленной другим потоком.
Чтобы лучше объяснить, что я имею в виду во втором пункте, япросматривал исходный код HashMap в OpenJdk 7
389 int hash = hash(key.hashCode());
390 int i = indexFor(hash, table.length);
Сначала он вычисляет хэш вашего ключа (объединяя две хеш-функции), затем он сопоставляется с ячейкой с indexFor
, тогда он проверяет, содержит ли эта ячейка тот же ключ или уже занят другим.Если это тот же ключ, он просто перезаписывает значение, и здесь нет проблем.
Если он занят, он смотрит на следующую ячейку, а затем на следующую, пока не найдет пустую позицию и не вызовет addEntry()
, который может даже решить изменить размер массива, если массив загружен больше, чем определенный loadFactor
.
Наш table
, содержащий записи, является просто вектором Entry
, который содержит ключ и значение.
146 /**
147 * The table, resized as necessary. Length MUST Always be a power of two.
148 */
149 transient Entry[] table;
В параллельной среде могут происходить всевозможные злые вещи, например, один поток получает столкновение для ячейки № 5, ищет следующую ячейку (6) и находит ее пустой.
Между тем другой поток получает индекс 6 в результате indexFor
, и оба решают использовать эту ячейку одновременно, один из двух перезаписывает другой.