Вопрос звучит просто: «почему ConcurrentHashMap быстрее Collections.synchronizedMap?» — но хороший ответ требует сказать не «он быстрее», а объяснить, что именно блокируется.

Collections.synchronizedMap оборачивает обычный HashMap одним общим монитором. Любая операция — get, put, containsKey — захватывает один и тот же лок на весь объект. Параллельные чтения двух потоков тоже блокируют друг друга, хотя логически им ничто не мешает читать одновременно.

ConcurrentHashMap в современных версиях (начиная с Java 8) не делит карту на сегменты с отдельными локами, как было раньше — вместо этого блокировка идёт на уровне отдельного бакета (узла в таблице) только на операции записи. Чтения через get вообще не берут лок — они используют volatile-семантику доступа к узлам таблицы.

Map map = new ConcurrentHashMap<>();

map.compute("key", (k, v) -> v == null ? 1 : v + 1 );

Дальше спросят про compute и computeIfAbsent: эти методы блокируют именно тот бакет, где лежит ключ, на всё время выполнения переданной функции. Если внутри лямбды случайно вызвать другую операцию на той же карте с тем же ключом — получите самодедлок, а не просто медленную операцию.

Разница не в «быстрее/медленнее» абстрактно, а в том, что один вариант сериализует весь доступ, а другой — только конкурентные записи в один и тот же бакет.

Тренажёр: 900+ вопросов и задач, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки