Ответ
Потокобезопасные коллекции находятся в пакете java.util.concurrent. Их можно разделить на несколько категорий.
1. Высокопроизводительные неблокирующие коллекции Используют механизмы сравнения с обменом (CAS) вместо блокировок (synchronized).
ConcurrentHashMap<K,V>: Потокобезопасный аналогHashMap. Обеспечивает высокий параллелизм за счёт внутренней сегментации (в более ранних версиях) или CAS-операций над узлами (Java 8+).ConcurrentHashMap<String, Integer> scores = new ConcurrentHashMap<>(); scores.put("Alice", 100); // Потокобезопасные атомарные операции: scores.computeIfAbsent("Bob", k -> 0); scores.merge("Alice", 50, Integer::sum);ConcurrentLinkedQueue<E>: Неблокирующая очередь на основе связного списка. Потокобезопасные операцииoffer()(добавление) иpoll()(извлечение).ConcurrentSkipListMap<K,V>/ConcurrentSkipListSet<E>: Потокобезопасные аналогиTreeMapиTreeSet, основанные на структуре данных "Skip List". Элементы хранятся в отсортированном порядке.
2. Коллекции с копированием при записи (Copy-On-Write) Идеальны для сценариев, где чтение происходит часто, а запись редко.
CopyOnWriteArrayList<E>: При каждой модификации (add,set,remove) создаётся новая копия внутреннего массива. Итераторы работают с "снимком" (snapshot) данных на момент создания и не бросаютConcurrentModificationException.CopyOnWriteArrayList<String> logMessages = new CopyOnWriteArrayList<>(); // Частое чтение многими потоками for (String msg : logMessages) { /* Безопасно */ } // Редкая запись logMessages.add("New log entry"); // Создаёт новую копию массиваCopyOnWriteArraySet<E>: РеализацияSetна основеCopyOnWriteArrayList.
3. Блокирующие очереди (Blocking Queues)
Реализуют интерфейс BlockingQueue. Потоки блокируются при попытке извлечь элемент из пустой очереди или добавить в полную.
ArrayBlockingQueue<E>: Очередь на основе массива фиксированной ёмкости (bounded).LinkedBlockingQueue<E>: Очередь на основе связного списка. Может быть как bounded, так и unbounded (по умолчаниюInteger.MAX_VALUE).PriorityBlockingQueue<E>: Блокирующая очередь с приоритетами (элементы должны реализовыватьComparable).BlockingQueue<Task> taskQueue = new LinkedBlockingQueue<>(100); // Производитель (Producer) taskQueue.put(new Task()); // Блокируется, если очередь полна // Потребитель (Consumer) Task task = taskQueue.take(); // Блокируется, если очередь пуста
4. Устаревшие синхронизированные обёртки
- Коллекции, создаваемые методами
Collections.synchronizedList(),synchronizedMap()и т.д. - Не рекомендуются для нового кода, так как обеспечивают потокобезопасность за счёт грубой блокировки всего объекта, что сильно снижает производительность при высокой конкуренции. Используйте коллекции из
java.util.concurrent.
Выбор коллекции зависит от преобладающей операции (чтение/запись), требований к производительности и необходимости блокировки потоков.