Java: Может ли чтение из HashMap изменить свое состояние?
Параллельные обновления для несинхронизированных HashMap
очевидно, может вызвать livelock или другие повреждения данных; чтобы избежать этого, следует использовать параллельную версию или реализовать механизм синхронизации.
Могут ли одновременные вызовы HashMap.get() изменить состояние HashMap, например, перефразирование?
Обновить:
Некоторые комментаторы задались вопросом о практических аспектах этого вопроса, помимо теоретической радости от придирки к поведению структуры данных.
Если get()
не меняет состояние HashMap
(и не может вызвать живую блокировку для другой причины), чем один поток может заранее создать HashMap, и тогда многие потоки могут читать из него одновременно. Если одновременное чтение не безопасно, нам нужно ConcurrentHashMap
для каждого многопоточного доступа, независимо от типа.
4 ответа
Из документов Java:
Если несколько потоков обращаются к хэш-карте одновременно, и хотя бы один из потоков структурно изменяет карту, она должна быть синхронизирована извне. (Структурная модификация - это любая операция, которая добавляет или удаляет одно или несколько сопоставлений; простое изменение значения, связанного с ключом, который уже содержится в экземпляре, не является структурной модификацией.)
Это означает, что одновременно get()
все в порядке и не приведет к изменению состояния.
Кроме того, вы всегда можете взглянуть на источник для получения дополнительной информации о том, как он построен.
Javadocs обычно определяют то, что считается структурной модификацией карты. HashMap утверждает, что get
это не операция, которая вызовет структурную модификацию.
Однако другие реализации карт ведут себя по-другому. Например, LinkedHashMap может использовать порядок доступа, в этом случае get
это структурная модификация:
В связанных хеш-картах с упорядоченным доступом простое обращение к карте с помощью get является структурной модификацией.
Только звоню get()
безусловно, не вызовет никаких проблем, как вы говорите. Однако одновременные несинхронизированные обновления, безусловно, могут быть причиной этого. В get()
метод, это только собирается вызвать hashcode()
метод для членов, пока не будет найдено совпадение. В этом случае обновление не будет выполнено.
Если вам, что знать, что происходит внутри HashMap.get()
(что является конкретной реализацией Map
интерфейс), вы можете прочитать код реализации.
Но для всех целей вам НЕ нужно заботиться о том, как реализована функция и что она делает! Единственная важная вещь - чтобы функция достигла своего контракта (API + класс / функция javadocs). Реализация может измениться в будущем, поэтому в зависимости от этого это плохая практика.