Java ConcurrentHashMap против Collections.synchronizedMap()

Java HashMap по умолчанию не синхронизирован. Если мы добавляем/удаляем пары ключ-значение из HashMap в параллельном приложении, где несколько потоков добавляют и удаляют пары, у нас может быть несогласованное состояние карты. Узнайте, как синхронизировать HashMap и разницу с ConcurrentHashMap в Java.

1. Класс ConcurrentHashMap

Наш первый выбор всегда должен быть с использованием класса ConcurrentHashMap, если мы хотим использовать Map в параллельной среде. ConcurrentHashMap поддерживает параллельный доступ к своим парам ключ-значение по замыслу. Нам не нужно выполнять никаких дополнительных изменений кода, чтобы включить синхронизацию на карте.

Обратите внимание, что Iterator, полученный из ConcurrentHashMap, не выдает ConcurrentModificationException. Однако итераторы предназначены для использования только одним потоком за раз. Это означает, что каждый итератор, который мы получаем из ConcurrentHashMap, предназначен для использования одним потоком и не должен передаваться.

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

Давайте рассмотрим пример работы с ConcurrentHashMap.

ConcurrentHashMap<Integer, String> concurrHashMap = new ConcurrentHashMap<>();//Put require no synchronizationconcurrHashMap.put(1, "A");concurrHashMap.put(2, "B");//Get require no synchronizationconcurrHashMap.get(1);Iterator<Integer> itr = concurrHashMap.keySet().iterator();//Using synchronized block is advisablesynchronized(concurrHashMap) {while(itr.hasNext()) {System.out.println(concurrHashMap.get(itr.next()));}}

Вывод программы.

AB

2. Коллекции.синхронизированнаяКарта()

Синхронизированный HashMap также работает очень похоже на ConcurrentHashMap, но имеет несколько отличий.

SynchronizedHashMap позволяет только одному потоку выполнять операции чтения/записи одновременно, поскольку все его методы объявлены синхронизированными. Concurrenthashmap позволяет нескольким потокам работать независимо над разными сегментами карты. Это обеспечивает более высокую степень параллелизма в ConcurrentHashMap и, таким образом, повышает общую производительность приложения.

Итераторы из обоих классов следует использовать внутри синхронизированного блока, но итератор из SynchronizedHashMap является отказоустойчивым. Итераторы ConcurrentHashMap не являются отказоустойчивыми.

Map<Integer, String> syncHashMap = Collections.synchronizedMap(new HashMap<>());//Put require no synchronizationsyncHashMap.put(1, "A");syncHashMap.put(2, "B");//Get require no synchronizationsyncHashMap.get(1);Iterator<Integer> iterator = syncHashMap.keySet().iterator();//Using synchronized block is advisablesynchronized(syncHashMap) {while(iterator.hasNext()) {System.out.println(syncHashMap.get(iterator.next()));}}

Вывод программы.

AB

3. Разница между синхронизированной HashMap и ConcurrentHashMap

Давайте выделим несколько различий между двумя версиями карт, чтобы мы могли решить, какую из них выбрать в зависимости от условий.

  • Несколько потоков могут добавлять/удалять пары ключ-значение из ConcurrentHashMap, тогда как в случае SynchronizedHashMap может вносить изменения только один поток. Это приводит к более высокой степени параллелизма в ConcurrentHashMap.
  • Нет необходимости блокировать карту для чтения значения в ConcurrentHashMap. Операция извлечения вернет значение, вставленное последней завершенной операцией вставки. Для операции чтения в SynchronizedHashMap также требуется блокировка.
  • ConcurrentHashMap не выдает исключение ConcurrentModificationException, если один поток пытается изменить его, пока другой выполняет итерацию по нему. Итератор отражает состояние карты на момент ее создания. SynchronizedHashMap возвращает Iterator, который быстро терпит неудачу при одновременном изменении.

4. Заключение

На основе приведенных выше аргументов можно сделать вывод, что использование ConcurrentHashMap всегда является лучшим выбором, если нам нужно создать новую Map. Используйте Collections.synchronizedMap(), когда у нас есть существующий экземпляр Map, и мы хотим его синхронизировать.

Напишите мне ваши вопросы, связанные с синхронизацией хэш-карты в Java.

Читать далее :
Документация Java HashMap
ConcurrentHashMap Java Документация

Исходный код на Github

Прокрутить вверх