Java中PriorityBlockingQueue的remove()方法
概述
Java中的PriorityBlockingQueue是一个基于优先级的阻塞队列,它可以保证队列中元素按照优先级的顺序被取出,而不是按照插入的顺序出队。PriorityBlockingQueue底层使用堆实现,并发度比较高,因此很受 Java开发人员的喜爱。
PriorityBlockingQueue是一个线程安全的队列,因此在多线程编程时可以直接使用。PriorityBlockingQueue是Queue接口的实现类,提供了remove()方法,该方法用于从队列中删除指定的元素,本篇文章将详细介绍PriorityBlockingQueue的remove()方法。
PriorityBlockingQueue的remove()方法
先来看一下PriorityBlockingQueue的remove()方法的源码:
public boolean remove(Object o) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = indexOf(o);
if (i == -1)
return false;
removeAt(i);
return true;
} finally {
lock.unlock();
}
}
从源码可以看出,remove()方法是一个public方法,返回一个boolean类型的值,用于从PriorityBlockingQueue中删除指定的元素。其中,重点需要了解的是indexOf()和removeAt()方法,这两个方法分别是用来查找和删除元素的。
indexOf()方法
看一下indexOf()方法的源码:
private int indexOf(Object o) {
if (o != null) {
Object[] es = queue;
int n = size;
for (int i = 1; i <= n; i++)
if (o.equals(es[i]))
return i;
}
return -1;
}
从源码可以看出,indexOf()方法是一个private方法,用于查找指定元素在PriorityBlockingQueue中的位置,其返回值为该元素在队列中的位置,如果不存在则返回-1。具体实现使用的是遍历数组的方式查找,查找的时间复杂度为O(n)。
removeAt()方法
来看一下removeAt()方法的源码:
private E removeAt(int i) {
final Object[] es = queue;
modCount++;
int n = size - 1;
if (n == i) // removed last element
es[i] = null;
else {
E moved = (E) es[n];
es[n] = null;
Comparator<? super E> c = comparator;
if (c == null)
siftDownComparable(i, moved, es, n);
else
siftDownUsingComparator(i, moved, es, n, c);
if (es[i] == moved) {
if (c == null)
siftUpComparable(i, moved, es);
else
siftUpUsingComparator(i, moved, es, c);
}
}
size = n;
return (E) es[i];
}
该方法中,首先通过获取队列中的元素数组queue,并对modCount计数器进行自增操作,标识PriorityBlockingQueue修改了一个元素。
然后,判断要删除的元素是否为队列中的最后一个元素。如果是,则直接将该元素赋值为null即可。
如果不是,先将队列中的最后一个元素移动到i位置(要删除的元素位置),然后分别使用siftDown()方法和siftUp()方法进行对比和移动,确保PriorityBlockingQueue的堆结构继续保持。
最后,将队列中的size减1,并在返回值之前将删除的元素赋值为null,以支持普通垃圾收集器回收。
remove()方法
从indexOf()和removeAt()方法的源码可以看出,remove()方法的主要作用是删除队列中指定的元素。先来看一下remove()方法的源码:
public boolean remove(Object o) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = indexOf(o);
if (i == -1)
return false;
removeAt(i);
return true;
} finally {
lock.unlock();
}
}
如上所述,remove()方法首先使用indexOf()方法查找指定元素在PriorityBlockingQueue中的位置,并进行判断,如果该元素不存在,则直接返回false;如果该元素存在,则调用removeAt()方法进行删除,并返回true表示删除成功。
需要注意的是,remove()方法使用了重入锁,以保证在并发环境下线程安全。
示例代码
下面提供一段使用PriorityBlockingQueue的示例代码,演示如何使用remove()方法。
import java.util.Comparator;
import java.util.concurrent.PriorityBlockingQueue;
class Task implements Comparable<Task> {
private int priority;
private String name;
public Task(int priority, String name) {
this.priority = priority;
this.name = name;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Task o) {
return this.priority - o.getPriority();
}
}
public class PriorityQueueDemo {
public static void main(String[] args) {
PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>(10,
Comparator.comparing(Task::getPriority).thenComparing(Task::getName));
Task task1 = new Task(1, "task1");
Task task2 = new Task(2, "task2");
Task task3 = new Task(3, "task3");
queue.offer(task1);
queue.offer(task2);
queue.offer(task3);
System.out.println("Before remove: ");
for (Task t : queue) {
System.out.println(t.getName());
}
queue.remove(task1);
System.out.println("\nAfter remove: ");
for (Task t : queue) {
System.out.println(t.getName());
}
}
}
在上述代码中,首先创建了一个PriorityBlockingQueue队列,类型为Task,元素数量为10。然后,创建了三个Task类型的对象,并将其插入到队列中。
接着,从队列中删除了task1(该元素的优先级为1),并将结果输出。
输出结果如下:
Before remove:
task1
task2
task3
After remove:
task2
task3
从输出结果可以看出,元素task1已经成功地从队列中删除了。
结论
综上所述,Java中的PriorityBlockingQueue是一个基于优先级的阻塞队列,具有并发度高、线程安全等优点。方法remove()是PriorityBlockingQueue提供的一个用于删除指定元素的方法,其底层调用了indexOf()和removeAt()两个方法来实现。
在使用PriorityBlockingQueue的remove()方法时,需要注意多线程并发情况下的安全问题,并确保被删除的元素一定存在于队列中。