Является ли метод put() в ConcurrentHashMap потокобезопасным в Java?

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

Ответ

Да, метод put() в ConcurrentHashMap является потокобезопасным. Он позволяет нескольким потокам безопасно модифицировать карту одновременно.

Как это работает:

  • В версиях до Java 8 используется сегментированная блокировка (lock striping), где блокируется только отдельный сегмент (бакет).
  • Начиная с Java 8, для большинства операций применяются оптимистичные блокировки на основе CAS (Compare-And-Swap) и synchronized на уровне отдельного узла (ноды) бакета, что повышает параллелизм.

Пример использования:

ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
// Потокобезопасные операции из разных потоков:
concurrentMap.put("keyA", 100);
concurrentMap.put("keyB", 200);

Важные нюансы:

  • Атомарность: Гарантируется атомарность одиночных операций (put(), get(), remove()).
  • Составные операции: Операции типа "проверить и вставить" (check-then-act) не являются атомарными при использовании отдельных вызовов. Для них следует использовать специальные методы, такие как putIfAbsent(), compute(), merge().
  • Итераторы: Итераторы, получаемые от ConcurrentHashMap (например, через entrySet().iterator()), являются слабо согласованными (weakly consistent). Они не бросают ConcurrentModificationException и могут отражать лишь часть изменений, произошедших после их создания.
  • null-значения: ConcurrentHashMap не разрешает использование null в качестве ключа или значения.