В чем разница между synchronized HashMap и ConcurrentHashMap в 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 обёртка подходит для простых случаев с низкой конкуренцией или для обеспечения совместимости с устаревшим кодом.

Ответ 18+ 🔞

Да ты посмотри, какая история-то, блядь! Сидят два этих ваших мапа, как два мужика в бане: один — старый, синхронизированный, весь в поту, блядь, сидит и держит дверь на замке, а другой — ConcurrentHashMap, хитрожопый, как швейцарский нож, блядь!

Вот этот ваш Collections.synchronizedMap(new HashMap<>()) — это ж классический мудак-охранник, ёпта. Зашёл один чувак в мапу — Герасим, блядь, — и всё, навесил здоровенный амбарный замок на всю коллекцию целиком. «Муму!» — кричит, а остальные стоят, блядь, в очереди, чешут репу. Хочешь положить ключ — стой, блядь. Хочешь просто прочитать, посмотреть — тоже, сука, стой и жди, пока Герасим свой мешок в озеро не бросит. Производительность, блядь, ниже плинтуса, как у этого немого силы — необоснованно много, а толку нихуя.

А ConcurrentHashMap — это уже, блядь, продвинутая система, как умный дом, ёбана! Он берёт эту большую мапу и делит её на сегменты — комнатки, блядь, отсеки. И в каждой комнатке — свой маленький замок, ебушки-воробушки! Один поток в одной комнате ключи перебирает, второй в соседней — значения записывает, и никто никому, блядь, не мешает! Это ж гениально просто, в рот меня чих-пых!

Короче, в чём разница, бля:

  1. Замки: У старого — один здоровенный на всю квартиру. У нового — куча маленьких на каждую комнату.
  2. Скорость: Новый — летает, как угорелый, когда потоков дохуя. Старый — ползёт, как рак с анальной пробкой.
  3. Финты ушами: ConcurrentHashMap умеет атомарные штуки делать одной командой: «добавь, если нет» или «возьми, прибавь единичку и запиши». Старый так не умеет, ему надо самому замок брать, проверять, писать — морока, блядь!
  4. Обход: Идешь ты по ConcurrentHashMap итератором — он тебе покажет всё, что было на момент старта, и не начнёт орать 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 и не парься, ёпта. Он для этого и сделан, чтобы всех этих нанайцев разгребать без потерь в производительности!