Карта / Коллекции / Concurrent коллекции

Concurrent коллекции

Обычные коллекции (ArrayList, HashMap) не потокобезопасны — если несколько потоков одновременно их меняют, можно получить повреждённые данные или ConcurrentModificationException. Для многопоточного кода есть специальные версии из java.util.concurrent.

Map<String, Integer> map = new ConcurrentHashMap<>();   // безопасно из нескольких потоков
map.put("счётчик", 1);

Подробнее про сам пакет java.util.concurrent — в теме «java.util.concurrent».

Копнуть глубже

ConcurrentHashMap — самая часто используемая. В отличие от старого Collections.synchronizedMap() (который блокирует всю карту целиком на каждой операции), ConcurrentHashMap блокирует только небольшую часть внутренней структуры — несколько потоков могут писать в разные участки одновременно.

CopyOnWriteArrayList — для случаев «читают часто, пишут редко». При каждой записи создаётся новая копия всего массива, зато чтение полностью без блокировок и без исключений при модификации во время обхода:

List<String> listeners = new CopyOnWriteArrayList<>();
// можно безопасно итерироваться, даже если кто-то добавит элемент во время обхода
Под капотом

ConcurrentHashMap использует комбинацию мелкой блокировки (lock striping — раньше) и CAS-операций (Compare-And-Swap, в современных версиях) — это позволяет нескольким потокам работать с разными частями карты по-настоящему параллельно, а не по очереди ждать одного общего замка. Подробнее про CAS — в теме «CAS».

CopyOnWriteArrayList оправдан только при редких записях — каждая запись копирует весь массив (O(n)), поэтому при частых изменениях он гораздо медленнее ConcurrentHashMap-подобных структур.

🎤 Закрыл тему, если можешь объяснить:
• почему обычные коллекции небезопасны в многопоточном коде;
• разницу между `ConcurrentHashMap` и `CopyOnWriteArrayList` и когда что выбрать (если дошёл до 2-го слоя).