Описание проблемы:
В Jdk1.7 механизм расширения HashMap принимает «метод вставки заголовка», то есть, когда хеш элемента достигает нового слота массива, он вставляется в заголовок связанного списка. Причина в том, что при добавлении элементов к хвосту временная сложность составляет O (n), а вставка головки может повысить производительность.
Хотя мы знаем, что HashMap не является потокобезопасным, этот способ записи вызовет проблемы со связанными списками с обратной связью при одновременном расширении (изменении размера).
Анализ причин:
void resize ( int newCapacity) { Entry [] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; возврат ; } Entry [] newTable = new Entry [newCapacity]; передача (newTable, initHashSeedAsNeeded (newCapacity)); table = newTable; Порог = ( int ) Math.min (newCapacity * loadFactor, MAXIMUM_CAPACITY + 1); } / ** * Переводит все записи из текущей таблицы в newTable. * / Void Transfer (Entry [] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entry <K, V> e: table) { while ( null ! = e) { Entry <K, V> next = e.next; // Эта строка кода? является кодом ключа, который вызывает проблему. if (rehash) { e.hash = null == e.key? 0 : hash (e.key); } int i =indexFor (e.hash, newCapacity); e.next = newTable [i]; newTable [i] = e; е = следующий; } } }