Java PriorityBlockingQueue
类
原文: https://howtodoinjava.com/java/collections/java-priorityblockingqueue/
Java PriorityBlockingQueue
类是并发阻塞队列数据结构实现,其中根据对象的优先级处理对象。 添加名称的“阻塞”部分意味着线程将阻塞等待,直到队列上有可用的项目为止。
在PriorityBlockingQueue
中,添加的对象根据其优先级进行排序。 默认情况下,优先级由对象的自然顺序决定。 队列构建时提供的比较器可以覆盖默认优先级。
优先阻塞队列
1. PriorityBlockingQueue
特性
让我们记下PriorityBlockingQueue
上的几个要点。
PriorityBlockingQueue
是一个无界队列,并且会动态增长。 默认初始容量为'11'
,可以在适当的构造器中使用initialCapacity
参数来覆盖。- 它提供了阻塞检索操作。
- 它不允许使用
NULL
对象。 - 添加到
PriorityBlockingQueue
的对象必须具有可比性,否则会抛出ClassCastException
。 - 默认情况下,优先级队列的对象以自然顺序排序。
- 比较器可用于队列中对象的自定义排序。
- 优先级队列的头是基于自然排序或基于比较器排序的最小元素。 当我们轮询队列时,它从队列中返回头对象。
- 如果存在多个具有相同优先级的对象,则它可以随机轮询其中的任何一个。
PriorityBlockingQueue
是线程安全的。- 方法
iterator()
中提供的Iterator
不能保证以任何特定顺序遍历PriorityBlockingQueue
的元素。 如果需要有序遍历,请考虑使用Arrays.sort(pbq.toArray())
。 rainToTo()
可用于按优先级顺序删除部分或全部元素,并将它们放置在另一个集合中。
2. Java PriorityBlockingQueue
示例
让我们看看对象的排序如何影响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;
}
@Override
public int compareTo(Employee emp) {
return this.getId().compareTo(emp.getId());
}
//Getters and setters
@Override
public 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 lambda 的比较器语法重新定义自定义顺序,并验证结果。 我们正在使用构造器PriorityBlockingQueue(int initialCapacity, Comparator comparator)
。
//Comparator for name field
Comparator<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 PriorityBlockingQueuerainTo()
示例
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 elements
priorityBlockingQueue.drainTo(list, 3);
System.out.println(list);
//Drain all elements
priorityBlockingQueue.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 : 1
Polled : 2
Polled : 3
3. Java PriorityBlockingQueue
构造器
PriorityBlockingQueue
类提供了 4 种不同的方法来用 Java 构造优先级队列。
PriorityBlockingQueue()
:构造一个空队列,其默认初始容量为(11),该初始容量根据其元素的自然顺序对其进行排序。PriorityBlockingQueue(Collection c)
:构造一个空队列,其中包含指定集合中的元素。PriorityBlockingQueue(int initialCapacity)
:构造具有指定初始容量的空队列,该队列根据其自然顺序对其元素进行排序。PriorityBlockingQueue(int initialCapacity, Comparator comparator)
:构造具有指定初始容量的空队列,该队列根据指定的比较器对其元素进行排序。
4. Java PriorityBlockingQueue
方法
您应该知道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 comparator()
:返回用于对此队列中的元素进行排序的比较器;如果此队列是根据其元素的自然顺序排序的,则返回null
。boolean contains(Object o)
:如果此队列包含指定的元素,则返回true
。Iterator iterator()
:在此队列中的元素上返回一个迭代器。int size()
:返回此队列中的元素数。int drainTo(Collection c)
:从此队列中删除所有可用元素,并将它们添加到给定的集合中。int drainTo(Collection c, int maxElements)
:从此队列中最多移除给定数量的可用元素,并将其添加到给定的集合中。int remainingCapacity()
:由于PriorityBlockingQueue
不受容量限制,因此始终返回Integer.MAX_VALUE
。Object[] toArray()
:返回包含此队列中所有元素的数组。
请注意
take()
和poll()
方法之间的区别。poll()
检索并删除此队列的头部,如果此队列为空,则返回null
。 它不阻止操作。
take()
检索并删除此队列的头部,如有必要,请等待直到元素可用。 它正在阻止操作。
5. 总结
在此 JavaPriorityBlockingQueue
教程中,我们学习了使用PriorityBlockingQueue
类的特性,该类可以按默认的自然顺序或自定义顺序(比较器)存储元素。
我们还了解了PriorityBlockingQueue
类的一些重要方法和构造器。
将我的问题放在评论部分。
学习愉快!
参考文献: