Ответ
Прямой потокобезопасный аналог ArrayList в пакете java.util.concurrent — CopyOnWriteArrayList.
Принцип работы:
При каждой операции модификации (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-коллекции могут быть эффективнее.
Ответ 18+ 🔞
Ага, слушай, вот тебе про эту вашу потокобезопасную хуйню. Прямой аналог ArrayList, только чтобы в потоках не пиздец наступал — это CopyOnWriteArrayList, сука.
Как оно, блядь, работает, этот цирк:
Каждый раз, когда ты пытаешься что-то туда запихнуть, поменять или выковырять (add, set, remove), оно, блядь, создаёт ПРОСТО НОВУЮ КОПИЮ всего внутреннего массива! Да, вот так вот, в рот меня чих-пых. Зато итераторы становятся неубиваемыми — они работают со старым снимком, который уже не меняется. Но запись, понятное дело, превращается в дорогую понтовую операцию.
Смотри, как это выглядит в коде:
import java.util.concurrent.CopyOnWriteArrayList;
List<String> concurrentList = new CopyOnWriteArrayList<>();
// Поток первый, придурок какой-то
concurrentList.add("Element1");
// Поток второй, итератор-мститель (ему похуй на изменения)
for (String item : concurrentList) {
System.out.println(item); // И никакого ConcurrentModificationException, ёпта!
}
Так когда же, блядь, это чудо-юдо использовать?
- Читаешь дохуя, пишешь раз в год. Классика — список слушателей какого-нибудь события.
- Когда коллекция маленькая, и тебе не жалко ресурсов на её постоянное клонирование.
- Когда безопасность итераторов для тебя — вопрос жизни и смерти, блядь.
А если не подходит, то что, сидеть и плакать?
Collections.synchronizedList(new ArrayList<>())- Ну, это для более-менее сбалансированных извращенцев, где и читают, и пишут поровну.
- Но, сука, при итерации надо синхронизировать вручную! Забыл — получи пизды.
List<String> syncList = Collections.synchronizedList(new ArrayList<>()); // Итерация? Захватывай монитор, пидор! synchronized(syncList) { for (String s : syncList) { /* ... */ } }
ConcurrentLinkedQueue— если тебе нужна не просто коллекция, а очередь (первый зашёл — первый вышел, вся эта хуйня).
Короче, вывод, блядь: CopyOnWriteArrayList — это как дорогой швейцарский нож, но только с одной лезвией «для чтения». Используй, если пишешь редко, а читаешь овердохуища. Для остального есть synchronizedList или другие конкурентные штуки, которые могут оказаться шустрее.