Ответ
Куча (например, PriorityQueue) по умолчанию не потокобезопасна. Проблемы возникают при параллельной модификации из нескольких потоков без внешней синхронизации, что приводит к состоянию гонки (race condition), повреждению внутренней структуры данных и неопределённому поведению.
Пример небезопасного использования:
PriorityQueue<Integer> heap = new PriorityQueue<>();
// Поток 1
new Thread(() -> heap.add(1)).start();
// Поток 2
new Thread(() -> heap.add(2)).start();
// Результат: возможны исключения ConcurrentModificationException,
// потеря данных или некорректная структура кучи.
Как обеспечить потокобезопасность:
- Использовать блокирующую версию из
java.util.concurrent:import java.util.concurrent.PriorityBlockingQueue; PriorityBlockingQueue<Integer> safeHeap = new PriorityBlockingQueue<>(); // Теперь операции add, poll, peek потокобезопасны. - Внешняя синхронизация с помощью
Collections.synchronizedCollection():Queue<Integer> syncHeap = Collections.synchronizedCollection(new PriorityQueue<>()); // Теперь необходим доступ через synchronized-блоки. - Явная синхронизация (наименее предпочтительно):
synchronized(heap) { heap.add(value); }
Ключевой вывод: Любая стандартная реализация кучи (PriorityQueue) небезопасна для многопоточного доступа "из коробки".