Вопрос звучит просто: «почему 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 — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки