Java 中 LinkedBlockingDeque 的 clear() 方法
LinkedBlockingDeque 是 Java 中的一个双向队列(Deque),底层基于链表实现,支持并发并且容量大小不受限制。在实际使用中,经常需要对队列中的元素进行清空操作。这时,我们可以使用 clear() 方法来清空队列中的全部元素。
LinkedBlockingDeque 简介
在开始讲解 clear() 方法之前,首先简要介绍一下 LinkedBlockingDeque。LinkedBlockingDeque 实现了 BlockingDeque 接口,提供了阻塞式队列所常用的各种方法,比如:addFirst、addLast、offerFirst、offerLast、takeFirst、takeLast 等。同时,该队列支持两种操作方式:可阻塞式(操作线程进入等待状态)和定时阻塞式(给定最长等待时间,到达时间后线程退出等待状态)。
在使用 LinkedBlockingDeque 时,我们通常会构造一个指定容量的队列,比如:
LinkedBlockingDeque<String> queue = new LinkedBlockingDeque<>(100);
当然,也可以创建一个不限容量的队列:
LinkedBlockingDeque<String> queue = new LinkedBlockingDeque<>();
接下来,我们就可以向队列中添加元素了:
queue.add("apple");
queue.offer("banana");
queue.put("carrot");
上述代码分别演示了向队列尾部追加元素的几种方式,其中,add() 方法如果队列已满会抛出异常,而 offer() 方法则会返回 false。与此对应的,put() 方法是一个阻塞式方法,当队列已满时会将调用线程阻塞,直到队列有了空余空间。如果我们要添加元素到队列头部,则可以使用 addFirst()、offerFirst() 或 putFirst() 方法。
队列中的元素如果不进行处理,则会一直保留在队列中。在某些场景中,我们需要清空队列中的所有元素,这时,就要使用 clear() 方法了。
LinkedBlockingDeque 的 clear() 方法
clear() 方法定义在 AbstractCollection 抽象类中,由于 LinkedBlockingDeque 实现了 Deque 接口,而该接口继承了 AbstractCollection 接口,因此 LinkedBlockingDeque 也继承了该方法。
public void clear() {
while (pollFirst() != null)
;
}
从上述代码中,我们可以看到,clear() 方法的主要作用是使用 pollFirst() 方法来逐一弹出队列头部元素,直到队列中没有元素为止。
pollFirst() 是双向队列中用于弹出队列头部元素的方法,其实现方式如下:
public E pollFirst() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
Node<E> first = head.next;
return (first == null) ? null : unlinkFirst(first);
} finally {
takeLock.unlock();
}
}
在 pollFirst() 中,首先获取到阻塞式的锁对象 takeLock,确保队列头部一次只能被一个线程访问。接着,获取头部节点 head 的下一个节点 first,如果该节点为空,则说明队列中没有元素,直接返回 null;否则,使用 unlinkFirst() 方法将该节点从队列中移除,并返回节点中的元素值。
private E unlinkFirst(Node<E> f) {
// assert takeLock.isHeldByCurrentThread();
Node<E> next = f.next;
E element = f.item;
f.item = null;
f.next = f; // help GC
head = next;
if (next == null)
last = null;
else
next.prev = null;
count--;
notFull.signal();
return element;
}
unlinkFirst() 方法将头部节点从链表中移除,并删除相关的引用,最后返回节点中的元素值。此外unlinkFirst() 方法还会更新队列中元素的数量 count,同时使用 notFull.signal() 方法来唤醒所有等待队列非满状态的线程,以便这些线程能够继续往队列中添加元素。
当 clear() 方法调用的时候,它会一直调用 pollFirst() 方法,直到队列中没有元素为止。这个过程中,每个弹出的元素都会分别被 unlinkFirst() 方法移除,并删除对应的引用。这样,我们就能够清空队列中所有的元素了。
示例
下面是一个使用 clear() 方法清空 LinkedBlockingQueue 的示例:
import java.util.concurrent.LinkedBlockingDeque;
public class Main {
public static void main(String[] args) {
LinkedBlockingDeque<String> queue = new LinkedBlockingDeque<>(100);
queue.add("apple");
queue.add("banana");
queue.add("carrot");
System.out.println("队列大小:" + queue.size()); // 输出队列大小:3
queue.clear();
System.out.println("队列大小:" + queue.size()); // 输出队列大小:0
}
}
在上述代码中,我们首先创建了一个大小为 100 的 LinkedBlockingQueue,然后向其中添加了三个元素。接着,我们使用 clear() 方法清空队列中所有元素,并输出队列大小。最终,输出结果为 0,验证了 clear() 方法的有效性。
结论
LinkedBlockingDeque 是一个支持并发访问的双向队列,单单使用 add()、offer()、put()、addFirst()、offerFirst()、putFirst() 来添加元素是不够的,有时还需要使用 clear() 方法来清空队列中的所有元素。
clear() 方法通过反复调用 pollFirst() 方法来逐一移除队列中的所有元素,并释放内存空间。在实际使用中,使用 clear() 方法能够优化内存占用,并降低代码复杂度。