BlockingQueue¶
BlockingQueue — это интерфейс в языке программирования Java, входящий в состав Java Collections Framework (пакет java.util.concurrent), который описывает потокобезопасную очередь с поддержкой операций ожидания. Введён в Java 5 (JSR 166) как часть пакета для поддержки многопоточного программирования. Основное отличие от стандартных коллекций — методы добавления и извлечения элементов могут блокировать текущий поток до тех пор, пока операция не станет возможной (например, очередь не освободится или не заполнится).
¶Основные характеристики
BlockingQueue реализует стандартный интерфейс Queue, но добавляет четыре набора методов для работы с элементами, каждый из которых ведёт себя по-разному в зависимости от состояния очереди (пустая или заполненная):
| Операция | Исключение | Специальное значение | Блокировка | Таймаут |
|---|---|---|---|---|
| Добавление | add(e) | offer(e) | put(e) | offer(e, time, unit) |
| Извлечение | remove() | poll() | take() | poll(time, unit) |
| Просмотр | element() | peek() | — | — |
- Методы с исключением (
add,remove,element) — при невозможности операции выбрасываютIllegalStateExceptionилиNoSuchElementException. - Методы со специальным значением (
offer,poll,peek) — возвращаютfalseилиnullвместо исключения. - Блокирующие методы (
put,take) — приостанавливают поток до тех пор, пока операция не выполнится. - Методы с таймаутом — блокируют поток на указанное время, после чего возвращают
falseилиnull.
Все реализации BlockingQueue являются потокобезопасными и не допускают хранения null-элементов (исключение — LinkedTransferQueue в некоторых версиях, но стандарт требует запрета).
¶Реализации
В стандартной библиотеке Java существует несколько реализаций интерфейса, различающихся внутренней структурой и поведением:
- ArrayBlockingQueue — ограниченная очередь на основе массива. Требует указания ёмкости при создании. Поддерживает опциональную политику справедливости (fairness) для потоков, ожидающих доступа.
- LinkedBlockingQueue — опционально ограниченная очередь на основе связного списка. По умолчанию имеет ёмкость
Integer.MAX_VALUE, что фактически делает её неограниченной. Часто используется в пулах потоков. - PriorityBlockingQueue — неограниченная очередь с приоритетом. Элементы упорядочиваются согласно естественному порядку или переданному компаратору.
- DelayQueue — неограниченная очередь, элементы которой становятся доступными для извлечения только после истечения заданной задержки (каждый элемент реализует интерфейс
Delayed). - SynchronousQueue — очередь без внутренней ёмкости. Каждая операция
putдолжна быть синхронизирована с операциейtakeв другом потоке. Используется для прямой передачи задач. - LinkedTransferQueue — неограниченная очередь, реализующая дополнительный интерфейс
TransferQueue, позволяющий потоку ожидать, пока другой поток примет элемент.
¶Применение
Основная область применения BlockingQueue — реализация паттерна «производитель-потребитель» (producer-consumer). Потоки-производители добавляют данные в очередь, потоки-потребители извлекают их. Блокирующее поведение автоматически координирует скорость работы потоков: потребитель ждёт, пока очередь не опустеет, а производитель — пока в ней не появится свободное место.
Типичные сценарии использования:
- Пулы потоков (например,
ThreadPoolExecutorиспользуетLinkedBlockingQueueилиArrayBlockingQueueдля хранения задач). - Системы обработки событий и сообщений.
- Буферизация данных между этапами конвейера обработки.
- Реализация очередей задач в веб-серверах и фреймворках.
¶Особенности и ограничения
- Методы
putиtakeявляются прерываемыми: если поток ожидает на блокирующей операции и получает сигнал прерывания, выбрасываетсяInterruptedException. - Ограниченные очереди (
ArrayBlockingQueue,LinkedBlockingQueueс заданной ёмкостью) предотвращают переполнение памяти при неограниченном производстве данных. - Не поддерживают
null-элементы, что исключает неоднозначность при проверке результата операцийpollиpeek. - Итераторы, возвращаемые реализациями, являются слабо согласованными (weakly consistent) и не гарантируют отражение всех изменений, произошедших после создания итератора.
¶Пример использования
```java BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
// Поток-производитель new Thread(() -> { try { queue.put("Сообщение"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start();
// Поток-потребитель new Thread(() -> { try { String msg = queue.take(); System.out.println(msg); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); ```
¶См. также
LinkedBlockingDeque— двунаправленная версия очереди.ConcurrentLinkedQueue— неблокирующая потокобезопасная очередь на основе CAS-операций.TransferQueue— расширение интерфейса для прямой передачи элементов.
¶Источники
- Документация Oracle Java SE: интерфейс
java.util.concurrent.BlockingQueue. - Брайан Гоetz, Тим Пирс, Джошуа Блох и др. «Java Concurrency on Practice» (2006).
- Документация OpenJDK, исходный код пакета
java.util.concurrent.