Выбор ответа Middle java.util.concurrent и виртуальные потоки спрашивают часто обновлено

Гонка на ConcurrentHashMap

Вопрос

Код if (!cache.containsKey(k)) cache.put(k, load(k)); выполняется в нескольких потоках, cache это ConcurrentHashMap. Что не так?

Попробуйте сами

Выберите вариант, и откроется разбор.

Показать ответ и разбор

Коротко

Правильный ответ: Check-then-act не атомарен: load вызовут дважды; нужен computeIfAbsent. Каждая операция ConcurrentHashMap потокобезопасна по отдельности, но между containsKey и put другой поток успевает сделать то же самое. computeIfAbsent выполняет вычисление атомарно для ключа.

Варианты ответа

  1. Check-then-act не атомарен: load вызовут дважды; нужен computeIfAbsentправильный ответ
  2. Ничего: ConcurrentHashMap сам делает такую пару вызовов атомарной
  3. Будет ConcurrentModificationException, если два потока вставят одно
  4. Будет дедлок, потому что put блокирует всю карту на время вызова load

Разбор

Каждая операция ConcurrentHashMap потокобезопасна по отдельности, но между containsKey и put другой поток успевает сделать то же самое. computeIfAbsent выполняет вычисление атомарно для ключа. CME concurrent-коллекции не бросают. put блокирует только одну корзину, не всю карту.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.

Термины по теме