Открыть сервисСервис

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.
Заметили ошибку или не согласны с информацией в статье? Напишите нам support@bfometr.ru