Является ли HashMap в Java потокобезопасной?

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

Ответ

Нет, HashMap не является потокобезопасной. При одновременной модификации из нескольких потоков без внешней синхронизации возможны:

  • Потеря данных при добавлении.
  • Повреждение внутренней структуры (например, образование циклических ссылок в бакетах), что может привести к бесконечному циклу при итерации.
  • ConcurrentModificationException при одновременной итерации и модификации.

Потокобезопасные альтернативы:

  1. ConcurrentHashMap (предпочтительный выбор):

    Map<String, String> concurrentMap = new ConcurrentHashMap<>();
    • Использует сегментированную блокировку или операции без блокировок (в новых версиях), что обеспечивает высокую производительность при параллельном чтении и записи.
    • Гарантирует атомарность отдельных операций (например, putIfAbsent).
  2. Collections.synchronizedMap() (обертка с глобальной блокировкой):

    Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
    • Синхронизирует все методы с помощью мьютекса на самом объекте-обертке.
    • Менее производительна при высокой конкуренции, так как блокирует всю коллекцию на время каждой операции.
    • Важно: Для безопасного перебора (iteration) всё равно необходимо использовать ручную синхронизацию:
      synchronized(syncMap) {
      for (Map.Entry<String, String> entry : syncMap.entrySet()) {
          // ...
      }
      }