Ответ
Стандартный ArrayList в Java не является потокобезопасным. Его использование из нескольких потоков без синхронизации приводит к неопределённому поведению и повреждению данных.
Потокобезопасные альтернативы:
-
CopyOnWriteArrayList(изjava.util.concurrent)- Принцип: При любой модификации (добавление, удаление) создаётся новая копия внутреннего массива. Итераторы работают с неизменяемым снимком (snapshot) на момент создания.
- Лучше всего подходит для сценариев с частым чтением и очень редкой записью.
-
Пример:
import java.util.concurrent.CopyOnWriteArrayList; CopyOnWriteArrayList<String> safeList = new CopyOnWriteArrayList<>(); safeList.add("Data"); // Итерация безопасна, даже если другой поток модифицирует список for (String item : safeList) { System.out.println(item); }
-
Collections.synchronizedList(new ArrayList<>())- Принцип: Возвращает обёртку, которая синхронизирует все методы исходного списка на одном мьютексе.
- Гарантирует атомарность отдельных операций (например,
add), но для составных операций (например, проверкаcontains, а затемadd) требуется внешняя синхронизация. - Пример:
List<String> syncList = Collections.synchronizedList(new ArrayList<>()); // Для итерации всё равно требуется ручная синхронизация synchronized(syncList) { for (String s : syncList) { // ... } }
Выбор зависит от паттерна доступа:
CopyOnWriteArrayList— для read-heavy workloads.synchronizedList— когда важна актуальность данных при записи, а операции чтения и записи сравнимы по частоте.