Класс Java PriorityBlockingQueue — это реализация структуры данных очереди с параллельным блокированием, в которой объекты обрабатываются на основе их приоритета. Часть имени «blocking» добавлена для того, чтобы указать, что поток будет блокироваться в ожидании, пока в очереди не появится доступный элемент.
В очереди приоритетной блокировки добавленные объекты упорядочиваются в соответствии с их приоритетом. По умолчанию приоритет определяется естественным порядком объектов. Приоритет по умолчанию может быть переопределен компаратором, предоставленным во время построения очереди.

1. Функции PriorityBlockingQueue
Давайте отметим несколько важных моментов относительно PriorityBlockingQueue.
- PriorityBlockingQueue — это неограниченная очередь, которая растет динамически. Начальная емкость по умолчанию — '11', ее можно переопределить с помощью параметра initialCapacity в соответствующем конструкторе.
- Обеспечивает блокировку операций по извлечению.
- Не допускается наличие объектов NULL.
- Объекты, добавляемые в PriorityBlockingQueue, ДОЛЖНЫ быть сопоставимыми, в противном случае будет выдана исключительная ситуация ClassCastException.
- Объекты приоритетной очереди по умолчанию упорядочены в естественном порядке.
- Компаратор можно использовать для индивидуального упорядочивания объектов в очереди.
- Голова приоритетной очереди — это наименьший элемент на основе естественного порядка или порядка на основе компаратора. Когда мы опрашиваем очередь, она возвращает головной объект из очереди.
- Если имеется несколько объектов с одинаковым приоритетом, он может опросить любой из них случайным образом.
- PriorityBlockingQueue является потокобезопасным.
- Iterator, предоставленный в методе iterator(), не гарантирует обход элементов PriorityBlockingQueue в каком-либо определенном порядке. Если вам нужен упорядоченный обход, рассмотрите возможность использования Arrays.sort(pbq.toArray()).
- Функция drainTo() может использоваться для удаления некоторых или всех элементов в порядке приоритета и помещения их в другую коллекцию.
2. Пример очереди приоритетной блокировки Java
Давайте посмотрим, как порядок объектов влияет на операции добавления и удаления в PriorityBlockingQueue. В приведенных примерах объекты имеют тип Employee. Класс Employee реализует интерфейс Comparable, который делает объекты сопоставимыми по полю 'id' сотрудника по умолчанию.
public class Employee implements Comparable<Employee> {private Long id;private String name;private LocalDate dob;public Employee(Long id, String name, LocalDate dob) {super();this.id = id;this.name = name;this.dob = dob;}@Overridepublic int compareTo(Employee emp) {return this.getId().compareTo(emp.getId());}//Getters and setters@Overridepublic String toString() {return "Employee [id=" + id + ", name=" + name + ", dob=" + dob + "]";}}
2.1 Естественный порядок
Пример Java PriorityBlockingQueue для добавления и опроса элементов, которые сравниваются на основе их естественного порядка.
PriorityBlockingQueue<Employee> PriorityBlockingQueue = new PriorityBlockingQueue<>();PriorityBlockingQueue.add(new Employee(1l, "AAA", LocalDate.now()));PriorityBlockingQueue.add(new Employee(4l, "CCC", LocalDate.now()));PriorityBlockingQueue.add(new Employee(5l, "BBB", LocalDate.now()));PriorityBlockingQueue.add(new Employee(2l, "FFF", LocalDate.now()));PriorityBlockingQueue.add(new Employee(3l, "DDD", LocalDate.now()));PriorityBlockingQueue.add(new Employee(6l, "EEE", LocalDate.now()));while(true){Employee e = PriorityBlockingQueue.poll();System.out.println(e);if(e == null) break;}
Вывод программы.
Employee [id=1, name=AAA, dob=2018-10-31]Employee [id=2, name=FFF, dob=2018-10-31]Employee [id=5, name=BBB, dob=2018-10-31]Employee [id=4, name=CCC, dob=2018-10-31]Employee [id=3, name=DDD, dob=2018-10-31]Employee [id=6, name=EEE, dob=2018-10-31]
2.2. Пример компаратора PriorityBlockingQueue
Давайте переопределим пользовательский порядок, используя синтаксис компаратора на основе лямбда-выражений Java 8, и проверим результат. Мы используем конструктор PriorityBlockingQueue(int initialCapacity, Comparator comparator).
//Comparator for name fieldComparator<Employee> nameSorter = Comparator.comparing(Employee::getName);PriorityBlockingQueue<Employee> PriorityBlockingQueue = new PriorityBlockingQueue<>( 11, nameSorter );PriorityBlockingQueue.add(new Employee(1l, "AAA", LocalDate.now()));PriorityBlockingQueue.add(new Employee(4l, "CCC", LocalDate.now()));PriorityBlockingQueue.add(new Employee(5l, "BBB", LocalDate.now()));PriorityBlockingQueue.add(new Employee(2l, "FFF", LocalDate.now()));PriorityBlockingQueue.add(new Employee(3l, "DDD", LocalDate.now()));PriorityBlockingQueue.add(new Employee(6l, "EEE", LocalDate.now()));while(true){Employee e = PriorityBlockingQueue.poll();System.out.println(e);if(e == null) break;}
Вывод программы.
Employee [id=1, name=AAA, dob=2018-10-31]Employee [id=5, name=BBB, dob=2018-10-31]Employee [id=4, name=CCC, dob=2018-10-31]Employee [id=3, name=DDD, dob=2018-10-31]Employee [id=6, name=EEE, dob=2018-10-31]Employee [id=2, name=FFF, dob=2018-10-31]
2.3. Пример PriorityBlockingQueue drainTo()
Пример Java, в котором используется метод drianTo() для извлечения нескольких элементов из очереди в одном операторе.
PriorityBlockingQueue<Integer> priorityBlockingQueue = new PriorityBlockingQueue<>();priorityBlockingQueue.add(1);priorityBlockingQueue.add(3);priorityBlockingQueue.add(2);priorityBlockingQueue.add(6);priorityBlockingQueue.add(4);priorityBlockingQueue.add(5);ArrayList<Integer> list = new ArrayList<>();//Drain first 3 elementspriorityBlockingQueue.drainTo(list, 3);System.out.println(list);//Drain all elementspriorityBlockingQueue.drainTo(list);System.out.println(list);
Вывод программы.
[1, 2, 3][1, 2, 3, 4, 5, 6]
2.4. Пример извлечения блокировки PriorityBlockingQueue
Пример Java для извлечения элементов из PriorityBlockingQueue с помощью блокирующего извлечения. Поток будет ждать, пока в очереди не появится элемент.
В данном примере поток ждет в очереди в бесконечном цикле, используя метод take(). Он ждет 1 секунду перед повторной проверкой. Как только мы добавляем элементы в очередь, он опрашивает элемент и выводит на консоль.
import java.util.concurrent.PriorityBlockingQueue;import java.util.concurrent.TimeUnit;public class PriorityQueueExample{public static void main(String[] args) throws InterruptedException{PriorityBlockingQueue<Integer> priorityBlockingQueue = new PriorityBlockingQueue<>();new Thread(() ->{System.out.println("Waiting to poll ...");try{while(true){Integer poll = priorityBlockingQueue.take();System.out.println("Polled : " + poll);Thread.sleep(TimeUnit.SECONDS.toMillis(1));}} catch(InterruptedException e) {e.printStackTrace();}}).start();Thread.sleep(TimeUnit.SECONDS.toMillis(2));priorityBlockingQueue.add(1);Thread.sleep(TimeUnit.SECONDS.toMillis(2));priorityBlockingQueue.add(2);Thread.sleep(TimeUnit.SECONDS.toMillis(2));priorityBlockingQueue.add(3);}}
Вывод программы.
Waiting to poll ...Polled : 1Polled : 2Polled : 3
3. Конструкторы очереди приоритетной блокировки Java
Класс PriorityBlockingQueue предоставляет 4 различных способа построения приоритетной очереди в Java.
- PriorityBlockingQueue() : создает пустую очередь с начальной емкостью по умолчанию(11), которая упорядочивает свои элементы в соответствии с их естественным порядком.
- PriorityBlockingQueue(Collection c) : создает пустую очередь, содержащую элементы указанной коллекции.
- PriorityBlockingQueue(int initialCapacity): создает пустую очередь с указанной начальной емкостью, которая упорядочивает свои элементы в соответствии с их естественным порядком.
- PriorityBlockingQueue(int initialCapacity, Comparator comparator) : создает пустую очередь с указанной начальной емкостью, которая упорядочивает свои элементы в соответствии с указанным компаратором.
4. Методы приоритетной блокировки очереди Java
Класс PriorityBlockingQueue имеет нижеприведенные важные методы, которые вам следует знать.
- boolean add(object) : вставляет указанный элемент в эту приоритетную очередь.
- boolean offer(object) : вставляет указанный элемент в эту приоритетную очередь.
- boolean remove(object) : удаляет один экземпляр указанного элемента из этой очереди, если он присутствует.
- Object poll() : извлекает и удаляет заголовок этой очереди, ожидая в течение указанного времени ожидания, если это необходимо, чтобы элемент стал доступен.
- Object poll(timeout, timeUnit): извлекает и удаляет заголовок этой очереди, ожидая в течение указанного времени ожидания, если это необходимо для того, чтобы элемент стал доступен.
- Object take() : извлекает и удаляет заголовок этой очереди, при необходимости ожидая, пока элемент станет доступным.
- void put(Object o) : вставляет указанный элемент в эту приоритетную очередь.
- void clear() : удаляет все элементы из этой приоритетной очереди.
- Компаратор comparator() : возвращает компаратор, используемый для упорядочивания элементов в этой очереди, или null, если эта очередь отсортирована в соответствии с естественным порядком ее элементов.
- boolean contains(Object o) : возвращает true, если эта очередь содержит указанный элемент.
- Итератор iterator() : возвращает итератор по элементам в этой очереди.
- int size() : возвращает количество элементов в этой очереди.
- int drainTo(Collection c) : удаляет все доступные элементы из этой очереди и добавляет их в указанную коллекцию.
- int drainTo(Collection c, int maxElements) : удаляет не более указанного количества доступных элементов из этой очереди и добавляет их в указанную коллекцию.
- int remainCapacity() : всегда возвращает Integer.MAX_VALUE, поскольку PriorityBlockingQueue не имеет ограничений по емкости.
- Object[] toArray() : возвращает массив, содержащий все элементы в этой очереди.
Обратите внимание на разницу между методами take() и poll(). Poll() извлекает и удаляет заголовок этой очереди или возвращает null, если эта очередь пуста. Это не блокирующая операция.
Take() извлекает и удаляет главу этой очереди, ожидая при необходимости, пока элемент не станет доступным. Это блокирующая операция.
5. Заключение
В этом руководстве по Java PriorityBlockingQueue мы научились использовать класс PriorityBlockingQueue, который может хранить элементы либо в естественном порядке по умолчанию, либо в пользовательском порядке, указанном компаратором.
Мы также изучили несколько важных методов и конструкторов класса PriorityBlockingQueue.
Пишите мне свои вопросы в разделе комментариев.
Ссылки: