ConcurrentHashMap, BlockingQueue
Тема дорожной карты · Java
Конкурентные Collections в Java — это потокобезопасные структуры данных в пакете java.util.concurrent, предназначенные для непосредственного использования несколькими потоками без внешней синхронизации, предлагающие значительно более высокую пропускную способность, чем оборачивание стандартных Collections через Collections.synchronizedMap(). ConcurrentHashMap является наиболее широко используемой — она разбивает карту на сегменты (Java 7) или использует блокировку бакетов на основе CAS (Java 8+), позволяя многочисленным конкурентным читателям и ограниченному числу конкурентных писателей без блокировки всей карты, что делает её предпочтительной заменой Hashtable в высококонкурентных Spring или JDBC-пулинговых сценариях. CopyOnWriteArrayList и CopyOnWriteArraySet гарантируют безопасность итерации, создавая свежую копию базового массива при каждой мутации, что делает их идеальными для случаев с интенсивным чтением и редкой записью, например реестров слушателей событий. Реализации BlockingQueue — LinkedBlockingQueue, ArrayBlockingQueue, PriorityBlockingQueue и SynchronousQueue — обеспечивают потокобезопасную передачу между производителями и потребителями с блокирующими операциями put() и take(), приостанавливающими потоки, а не заставляющими их крутиться в ожидании; они формируют основу рабочих очередей Java Executor Framework. ConcurrentLinkedQueue и ConcurrentLinkedDeque предлагают неблокирующие, свободные от блокировок операции с очередью на основе CAS, подходящие для сценариев, где производителям и потребителям нужна максимальная пропускная способность без накладных расходов на блокировку.
Как это работает
ConcurrentHashMap, BlockingQueue имеет много инструментов: Thread (низкоуровневый), Executor / ExecutorService (пулы потоков), CompletableFuture (async-композиция), Future, java.util.concurrent коллекции (ConcurrentHashMap, BlockingQueue, CopyOnWriteArrayList), атомарные примитивы (AtomicInteger, AtomicReference). Java 21 даёт virtual threads (Project Loom — миллионы лёгких потоков, идеально для I/O-bound). Синхронизация: synchronized, ReentrantLock, ReadWriteLock, StampedLock. Memory model (JMM) управляет видимостью.
Когда применять
ExecutorService вместо сырых Thread — пулы управляют жизненным циклом. CompletableFuture — для async-композиции (thenApply, thenCompose, allOf). На Java 21+ virtual threads делают блокирующий I/O практичным на высокой конкурентности (Executors.newVirtualThreadPerTaskExecutor()). ConcurrentHashMap — для shared-state. Прочтите "Java Concurrency in Practice" до серьёзного concurrent-кода.
Типичные ошибки
Ловушки ConcurrentHashMap, BlockingQueue: shared mutable state без синхронизации (visibility-баги); volatile-"фикс" для race, требующих атомарности (volatile только видимость, не атомарный RMW); deadlock из-за двух локов в разном порядке; не daemon-threads когда нужно (JVM висит при shutdown); слишком много потоков для I/O-bound до Loom (новый ответ — virtual threads).