Должен ли я синхронизировать общий ресурс (изменяемый) во время чтения? - PullRequest
0 голосов
/ 07 августа 2020

У меня есть HashMap, который используется несколькими потоками. И любой поток может его обновить. Поэтому я синхронизирую объект HashMap при его обновлении.

Следует ли мне синхронизировать и во время чтения? ИЛИ достаточно сделать его нестабильным?

Примечание: Я знаю, что могу просто использовать ConcurentHashMap, но хочу знать, влияет ли многопоточность на чтение изменяемых общих ресурсов. Если да, то как это влияет на ?

А что, если это простой объект (не коллекция) или примитивный тип.

Ответы [ 3 ]

1 голос
/ 07 августа 2020

В Java HashMap документации указано (выделено жирным шрифтом в оригинале):

Обратите внимание, что эта реализация не синхронизирована. Если несколько потоки обращаются к карте ha sh одновременно, и по крайней мере один из потоков структурно модифицирует карту, он должен быть синхронизирован извне. (Структурная модификация - это любая операция, которая добавляет или удаляет одно или несколько сопоставлений; простое изменение значения, связанного с ключом, который уже содержится в экземпляре, не является структурной модификацией.) Обычно это выполняется путем синхронизации на некотором объекте, который естественным образом инкапсулирует карту. . Если такого объекта не существует, карту следует «обернуть» с помощью метода Collections.synchronizedMap. Лучше всего это делать во время создания, чтобы предотвратить случайный несинхронизированный доступ к карте:

Map m = Collections.synchronizedMap(new HashMap(...));

Итераторы, возвращаемые всеми «методами представления коллекции» этого класса: безотказно : если карта структурно изменена в любое время после создания итератора, любым способом, кроме как с помощью собственного метода удаления итератора, итератор выдаст ConcurrentModificationException. Таким образом, перед лицом параллельной модификации итератор выходит из строя быстро и чисто, вместо того, чтобы рисковать произвольным, недетерминированным c поведением в неопределенное время в будущем.

Обратите внимание, что безотказное поведение итератор не может быть гарантирован, поскольку, вообще говоря, невозможно дать какие-либо жесткие гарантии при наличии несинхронизированной параллельной модификации. Отказоустойчивые итераторы выдают ConcurrentModificationException по принципу максимальных усилий. Следовательно, было бы неправильно писать программу, правильность которой зависела бы от этого исключения: отказоустойчивое поведение итераторов должно использоваться только для обнаружения ошибок.

Вы не может безопасно изменить HashMap при чтении из него. Можете ли вы безопасно подняться по лестнице, пока ступеньки убираются?

1 голос
/ 07 августа 2020

Вам также необходимо выполнить синхронизацию во время чтения или переключиться на использование ConcurrentHashMap.

Если один поток вызывает метод get, а другой поток обновляет карту, невозможно предсказать, что произойдет. Метод get может вызвать исключение, поскольку предполагает, что внутренняя структура карты не изменяется во время ее работы.

0 голосов
/ 17 августа 2020

Вы также должны синхронизировать сторону чтения, потому что любые гарантии (видимость в вашем случае) применяются только тогда, когда потоки используют одну и ту же блокировку, поэтому, когда вы пропускаете синхронизацию во время чтения - это означает, что поток чтения не использует ту же блокировку (это не не использовать блокировку), что приведет к просмотру устаревших значений при чтении потока. См. Здесь: Следует ли синхронизировать геттеры и сеттеры?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...