2016-08-04 10 views
1

У нас есть приложение, которое использовало экземпляр java.util.HashMap, который - через различные косвенные отношения - делится так, чтобы несколько потоков обращались к нему одновременно. Мы зафиксировали это на данный момент, поскольку мы знаем, что java.util.HashMap не является потокобезопасным и не должен быть доступен одновременно.HashMap зависает при одновременном доступе

До этого исправления, и поэтому мы выяснили, у нас было обновление в JDK (в IBM JDK 7 SR3) и после что обновления мы испытали случайные зависания во время ПОЛУЧИТЬ операций этого экземпляра HashMap (зависание происходит в методе getEntry().)

Из любопытства я хотел бы знать, что происходит внутри HashMap, что вызывает зависание. Какая разница в реализации, которая влияет на поведение при одновременном доступе?

Что касается реализации HashMap, IBM JDK такой же, как у Oracle JDK и OpenJDK, который снова отличается от версии Java8 (с использованием datastructure Node).

Я считаю, что difference between java7u40 b43 vs b147 представляет собой изменение, которое было внесено с обновлением.

Мое текущее предположение, причиной зависание связано с изменением метода addEntry, переходя от надстройки первого-размер-после в изменение размера-первых, надстройку после.

Но есть ли у кого-то точное понимание, что именно происходит во время одновременного доступа?

+0

Гонки данных по своему определению непредсказуемы и случайны. Изменения в JDK, возможно, были небольшим изменением, где-то полностью не связанным, что заставило некоторый процесс нанести наносекунду дольше, раздражая проблему. Скорее всего, вопрос о том, что там все время, но перешел от одного в несколько миллионов шансов на одного в несколько тысяч. Не воссоздавая проблему и принимая дамп потока, почти невозможно определить причину. Безопасность нитей не может быть доказана путем тестирования, но только путем тщательного анализа кода. –

+0

В 'HashMap' нет методов' getEntry() 'и' addEntry() '. Ты уверен, что там ты повесишь? –

+0

@ OlivierGrégoire есть внутри. –

ответ

0

Я закончил отладку модульного теста, который мы написали, и проверил ведра HashMap, когда нить висит/петли. И действительно, они создают цикл в ковше, когда два потока одновременно изменяют размер карты. Он заканчивает со структурой, как это:

bucket1[0].entry1.next = entry2; 
bucket1[0].entry2.next = entry1; 

Более подробное описание можно найти здесь Resizing the HashMap: dangers ahead

1

Когда hashmap.put (ключ, значение) вызывается, порог HashMap проверяется. Если размер карты превышает этот порог, карта будет изменена, и все записи будут перезаписаны.
В многопоточной среде это оставит ваш HashMap в несогласованном состоянии. По крайней мере, вы должны защищать вызовы в приложении, которые записывают в HashMap с помощью синхронизации или блокировок.
Я рекомендую использовать java.util.concurrent.ConcurrentHashMap.

 Смежные вопросы

  • Нет связанных вопросов^_^