Какой потокобезопасный аналог ArrayList существует в Java Concurrent Collections?

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

Ответ

Прямой потокобезопасный аналог ArrayList в пакете java.util.concurrentCopyOnWriteArrayList.

Принцип работы: При каждой операции модификации (add, set, remove) создается новая копия внутреннего массива. Это обеспечивает безопасность итераторов (они работают с неизменяемым снимком), но делает операции записи затратными.

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

import java.util.concurrent.CopyOnWriteArrayList;

List<String> concurrentList = new CopyOnWriteArrayList<>();

// Поток 1
concurrentList.add("Element1");

// Поток 2 (итерация безопасна, даже если список изменяется)
for (String item : concurrentList) {
    System.out.println(item); // Нет ConcurrentModificationException
}

Когда использовать CopyOnWriteArrayList:

  • Частое чтение, очень редкая запись. (Например, список слушателей событий).
  • Когда размер коллекции небольшой, чтобы стоимость копирования была приемлемой.
  • Когда критически важна безопасность итераторов.

Альтернативы для других сценариев:

  • Collections.synchronizedList(new ArrayList<>())
    • Подходит для более сбалансированной нагрузки чтение/запись.
    • Требует ручной синхронизации при итерации!
      List<String> syncList = Collections.synchronizedList(new ArrayList<>());
      // При итерации нужно синхронизировать
      synchronized(syncList) {
      for (String s : syncList) { /* ... */ }
      }
  • ConcurrentLinkedQueue — если нужна потокобезопасная очередь (FIFO).

Вывод: CopyOnWriteArrayList — специализированная реализация для сценариев «чтение-много, запись-мало». Для общего случая synchronizedList или другие concurrent-коллекции могут быть эффективнее.