Из чего использование ConcurrentHashMap
в Java? Каковы его преимущества?Как это работает? Пример кода был бы полезен также.
Дело в том, чтобы предоставить реализацию HashMap
, которая является потокобезопасной. Несколько потоков могут читать и записывать в него без возможности получения устаревших или поврежденных данных. ConcurrentHashMap
обеспечивает собственную синхронизацию, поэтому вам не нужно явно синхронизировать доступ к ней.
Другой особенностью ConcurrentHashMap
является то, что он предоставляет метод putIfAbsent
, который атомарно добавляет отображение, если указанный ключ не существует. Рассмотрим следующий код:
ConcurrentHashMap<String, Integer> myMap = new ConcurrentHashMap<String, Integer>();
// some stuff
if (!myMap.contains("key")) {
myMap.put("key", 3);
}
Этот код не является потокобезопасным, потому что другой поток может добавить отображение для «ключ»
между вызовом содержит
и вызовом положить
. Правильная реализация:
myMap.putIfAbsent("key", 3);
Действительно, большая функциональная разница в том, что она не вызывает исключения и/или не повреждается, когда кто-то другой изменяет ее, пока вы ее используете.
В обычных коллекциях, если другой поток добавляет или удаляет элемент, пока вы обращаетесь к нему (через итератор), это вызовет исключение. ConcurrentHashMap позволяет им внести изменения и не останавливает ваш поток.
Следует помнить, что он не дает никаких гарантий синхронизации или обещаний относительно видимости изменения в момент времени от одного потока к другому. (Это похоже на изоляцию базы данных с фиксацией чтения, а не на синхронизированную карту, которая ведет себя скорее как сериализуемая изоляция базы данных. (Сериализуемый SQL с блокировкой строк старой школы, а не многоверсионный сериализуемый Oracle :) )
Наиболее распространенное использование, о котором я знаю, это кэширование неизменяемой производной информации в средах App Server, где многие потоки могут обращаться к одной и той же вещи, и не имеет значения, если два потока вычисляют одно и то же значение кэша и помещают его дважды, потому что они чередуются и т.д. (например, он широко используется в Spring WebMVC для хранения производных конфигураций, полученных во время выполнения, таких как отображения URL на методы обработчиков)
.