В чем разница между synchronized HashMap и ConcurrentHashMap в Java?

«В чем разница между synchronized HashMap и ConcurrentHashMap в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Synchronized HashMap (Collections.synchronizedMap(new HashMap<>())) использует глобальную блокировку (монитор всей коллекции) на время операций. Это безопасно, но сильно снижает производительность при высокой конкуренции потоков, так как блокируется даже чтение.

ConcurrentHashMap использует технику сегментированной блокировки (lock striping). Коллекция делится на сегменты (бакеты), и блокировка происходит на уровне отдельного сегмента. Это позволяет многим потокам работать с разными сегментами одновременно.

Ключевые отличия:

  1. Гранулярность блокировки: Глобальная vs. на уровне сегмента.
  2. Производительность: ConcurrentHashMap обеспечивает гораздо более высокий throughput в многопоточных сценариях.
  3. Атомарные операции: ConcurrentHashMap предоставляет потокобезопасные атомарные методы (putIfAbsent(), compute(), merge()), которых нет у synchronized обёртки.
  4. Итераторы: Итераторы 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 обёртка подходит для простых случаев с низкой конкуренцией или для обеспечения совместимости с устаревшим кодом.