Ответ
Synchronized HashMap (Collections.synchronizedMap(new HashMap<>())) использует глобальную блокировку (монитор всей коллекции) на время операций. Это безопасно, но сильно снижает производительность при высокой конкуренции потоков, так как блокируется даже чтение.
ConcurrentHashMap использует технику сегментированной блокировки (lock striping). Коллекция делится на сегменты (бакеты), и блокировка происходит на уровне отдельного сегмента. Это позволяет многим потокам работать с разными сегментами одновременно.
Ключевые отличия:
- Гранулярность блокировки: Глобальная vs. на уровне сегмента.
- Производительность:
ConcurrentHashMapобеспечивает гораздо более высокий throughput в многопоточных сценариях. - Атомарные операции:
ConcurrentHashMapпредоставляет потокобезопасные атомарные методы (putIfAbsent(),compute(),merge()), которых нет у synchronized обёртки. - Итераторы: Итераторы
ConcurrentHashMapработают по «снимку» (snapshot) или слабо согласованному представлению и не бросаютConcurrentModificationException.
Пример создания:
// Медленно, но просто для низкой конкуренции
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
// Высокопроизводительная потокобезопасная мапа
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
// Атомарное обновление
concurrentMap.compute("key", (k, v) -> (v == null) ? 1 : v + 1);
Когда использовать: ConcurrentHashMap — стандартный выбор для высоконагруженных многопоточных приложений. Synchronized обёртка подходит для простых случаев с низкой конкуренцией или для обеспечения совместимости с устаревшим кодом.