Оригинальная статья и краткое изложение опыта и жизненные перипетии от набора в школу до фабрики А
Нажмите, чтобы узнать подробностиwww.codercc.com
1. Введение в BlockingQueue
В реальном программировании часто используются различные классы-контейнеры в среде Collection в JDK, например, реализующие интерфейсы List, Map и Queue, но эти классы-контейнеры в основном не потокобезопасны, за исключением того, что их можно преобразовать с помощью Коллекции Для потокобезопасных контейнеров мастер Дуг Ли подготовил для нас соответствующие потокобезопасные контейнеры, такие как CopyOnWriteArrayList, который реализует интерфейс List (См. эту статью о CopyOnWriteArrayList), ConcurrentHashMap, реализующий интерфейс Map (См. эту статью о ConcurrentHashMap), ConcurrentLinkedQueue, реализующий интерфейс Queue (Вы можете прочитать эту статью о ConcurrentLinkedQueue).
чаще всего используется»производитель-потребитель«В задаче очередь обычно рассматривается как контейнер данных для межпоточных операций, чтобы можно было разделить бизнес-функции каждого модуля, производитель помещает «произведенные» данные в контейнер данных, а потребителю нужны только к Данные могут быть получены в «контейнере данных», так что поток производителя и поток потребителя могут быть отделены и сосредоточены только на их собственных бизнес-функциях.BlockingQueue широко используется в «производитель-потребитель». блокируемые методы введения и удаления.Когда контейнер очереди заполнен, поток-производитель будет заблокирован до тех пор, пока очередь не будет заполнена; когда контейнер очереди пуст, поток-потребитель будет заблокирован до тех пор, пока очередь не станет пустой.
2. Основные операции
Основные операции BlockingQueue резюмируются следующим образом (этот рисунок взят из документации JAVA API):
BlockingQueue наследуется от интерфейса Queue, поэтому основными операциями с элементами данных являются:
вставить элемент
- add(E e) : Вставить данные в очередь.Когда очередь заполнена, при вставке элементов будет выброшено исключение IllegalStateException;
- offer(E e): при вставке данных в очередь вставка возвращается успешно
true
, иначе возвратfalse
. При заполнении очереди исключений не будет.
удалить элемент
- remove(Object o): удалить данные из очереди, вернуться в случае успеха
true
, в противном случаеfalse
- опрос: удалить данные, когда очередь пуста, вернуть ноль;
Просмотр элементов
- element: получает элемент в начале очереди и генерирует исключение NoSuchElementException, если очередь пуста;
- peek: Получить главный элемент очереди, выдать NoSuchElementException, если очередь пуста.
Специальные операции, которые есть у BlockingQueue:
Вставить данные:
- put: когда емкость очереди блокировки заполнена, поток, вставляющий данные в очередь блокировки, будет заблокирован до тех пор, пока в очереди блокировки не появится свободная емкость для использования;
- offer(E e, long timeout, TimeUnit unit): если очередь блокировки заполнена, поток, который вставляет данные, также будет заблокирован до тех пор, пока в очереди блокировки не останется места. В отличие от метода put, этот метод будет иметь период ожидания, если текущий заданный период тайм-аута превышен, поток, который вставляет данные, завершится;
удалить данные
- take(): когда блокирующая очередь пуста, поток, который получает данные заголовка очереди, будет заблокирован;
- poll(длинный тайм-аут, блок TimeUnit): когда очередь блокировки пуста, поток, который получает данные, будет заблокирован. Кроме того, если заблокированный поток превышает заданное время, поток завершится
3. Обычно используется BlockingQueue
Реализуйте интерфейс BlockingQueue с помощьюArrayBlockingQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, LinkedTransferQueue, PriorityBlockingQueue, SynchronousQueue
, и эти общие очереди блокировки также часто используются в реальном программировании.Далее описаны эти общие очереди блокировки:
1.ArrayBlockingQueue
ArrayBlockingQueueпредставляет собой ограниченную блокирующую очередь, реализованную массивом. Элементы команды очереди — FIFO (первым пришел, первым вышел). Таким образом, головной элемент — это элемент данных с наибольшим временем пребывания в очереди, а хвостовые данные — самый последний элемент данных в текущей очереди. ArrayBlockingQueue может действовать как «ограниченный буфер данных», где производители вставляют данные в контейнер очереди, а потребители извлекают их. После создания очереди ArrayBlockingQueue ее емкость нельзя изменить.
Попытка поместить элемент в очередь, когда очередь заполнена, приведет к блокировке операции; попытка извлечения элемента из пустой очереди также приведет к блокировке.
ArrayBlockingQueue не может гарантировать справедливость очереди доступа к потоку по умолчанию.Так называемая справедливость относится строго к абсолютному временному порядку ожидания потока, то есть первый ожидающий поток может получить доступ к ArrayBlockingQueue первым. Несправедливость означает, что порядок доступа к ArrayBlockingQueue не является строго хронологическим.Может существовать так, что после того, как к ArrayBlockingQueue можно получить доступ, поток, который был заблокирован в течение длительного времени, все еще не может получить доступ к ArrayBlockingQueue.Обычно более низкая пропускная способность, если гарантируется справедливость. Если вам нужна справедливая ArrayBlockingQueue, вы можете использовать следующий код:
private static ArrayBlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(10,true);
Что касается принципа реализации ArrayBlockingQueue, вы можетесм. эту статью.
2.LinkedBlockingQueue
LinkedBlockingQueue — это ограниченная очередь блокировки, реализованная со связанным списком. Она также удовлетворяет характеристикам FIFO. По сравнению с ArrayBlockingQueue имеет более высокую пропускную способность. Чтобы предотвратить быстрое увеличение емкости LinkedBlockingQueue, она потребляет много памяти. Обычно при создании объекта LinkedBlockingQueue указывается его размер, если не указан, емкость равна Integer.MAX_VALUE
3.PriorityBlockingQueue
PriorityBlockingQueue — неограниченная очередь блокировки, поддерживающая приоритет. По умолчанию элементы сортируются в естественном порядке.Вы также можете указать правила сортировки элементов, реализуя метод compareTo() пользовательского класса, или указать правила сортировки через параметр конструктора Comparator во время инициализации.
4.SynchronousQueue
Каждая операция вставки SynchronousQueue должна ждать, пока другой поток выполнит соответствующую операцию удаления. Следовательно, SynchronousQueue на самом деле не хранит никаких элементов данных, потому что только когда поток удаляет данные, другие потоки могут вставлять данные. Аналогично, если в данный момент существует поток вставляя данные, поток может удалить данные. SynchronousQueue также может указывать справедливость с помощью параметров конструктора.
5.LinkedTransferQueue
LinkedTransferQueue — это неограниченная очередь блокировки, состоящая из структуры данных связанного списка.Поскольку очередь реализует интерфейс TransferQueue, она в основном имеет следующие методы, отличные от других очередей блокировки:
transfer(E e)Если поток (потребитель) в настоящее время вызывает метод take() или метод deferrable poll() для потребления данных, поток-производитель может вызвать метод передачи для передачи данных потоку-потребителю. Если в настоящее время нет потока-потребителя, поток-производитель вставит данные в конец очереди и не завершится до тех пор, пока потребитель не сможет их использовать;
tryTransfer(E e)В методе tryTransfer, если поток-потребитель (вызывающий метод take или метод опроса с функцией тайм-аута) в настоящее время потребляет данные, этот метод может немедленно передать данные в поток-потребитель и немедленно вернуться, если в данный момент нет потока-потребителя, потребляющего данные.false
. Следовательно, по сравнению с методом передачи, метод передачи должен ждать, пока поток-потребитель не получит данные, прежде чем поток-производитель сможет вернуться. Метод tryTransfer может немедленно вернуть результат и выйти.
tryTransfer(E e,long timeout,imeUnit unit)
Это то же самое, что и основная функция передачи, за исключением того, что добавлена функция тайм-аута.Если данные не потребляются потребителями в течение указанного периода тайм-аута, они будут возвращеныfalse
.
6.LinkedBlockingDeque
LinkedBlockingDeque — это двусторонняя очередь с ограниченной блокировкой, основанная на структуре данных связанного списка.Если размер указывается при создании объекта, его размер по умолчанию — Integer.MAX_VALUE. По сравнению с LinkedBlockingQueue основное отличие заключается в том, что LinkedBlockingDeque имеет характеристики двусторонней очереди. Базовая работа LinkedBlockingDeque показана на следующем рисунке (из документации по java).
Как показано на рисунке выше, основные операции LinkedBlockingDeque можно разделить на четыре типа: 1. В особых случаях выбрасывается исключение; 2. В особых случаях возвращаются специальные значения, такие как null или false; 3. Когда поток не соответствует условиям работы, поток будет заблокирован до тех пор, пока условие не будет выполнено 4. Операция имеет свойство тайм-аута.
Кроме того, LinkedBlockingDeque реализует интерфейс BlockingDueue, а LinkedBlockingQueue реализует BlockingQueue Основное различие между двумя интерфейсами показано на следующем рисунке (из документации по java):
Как видно из приведенного выше рисунка, функции двух интерфейсов могут использоваться эквивалентно, например, функции метода add BlockingQueue и метода addLast BlockingDeque одинаковы.
7.DelayQueue
DelayQueue — неограниченная блокирующая очередь, в которой хранятся данные, реализующие интерфейс Delayed.Только по достижении времени задержки объекта данных он может быть вставлен в очередь на хранение. Если все текущие данные не достигли периода задержки, указанного при создании, очередь не имеет заголовка очереди, и поток возвращает null, если элемент данных получен такими методами, как опрос. Когда так называемая задержка данных истекает, они передаются через интерфейс Delayed.getDelay(TimeUnit.NANOSECONDS)
Судя по всему, если метод возвращает меньше или равно 0, это означает, что период задержки элемента данных истек.