Java阻塞队列必看类:BlockingQueue快速了解大体框架和实现思路
前言
本文主要说明BlockingQueue类、阻塞队列使用的共同父类AbstractQueue的基础知识。后续将会逐渐探索BlockingQueue的所有实现类。
BlockingQueue
概览
1. 不接受null元素。
通过新增方法添加null元素时,会抛出空指针异常。因为null值将用作标记值,来指明poll操作失败。同时null值作为阻塞队列的元素也是无任何意义的。
2. 可以有容量限制,也可以没有。
当作为有界队列时,如果当队列空间不足时,add操作将会抛出IllegalStateException异常,offer将会返回false,put操作将会阻塞直到队列空间可用。
如果不设置容量大小,那么默认值是Integer.MAX_VALUE。此时可以看作无界队列;
虽然队列在逻辑上可以是无界的,但由于资源耗尽(导致OutOfMemoryError ),添加操作可能会失败。
3. 用于生产者-消费者队列,但是同时也支持Collection的操作。
例如删除队列元素操作remove(e),但是这些操作的效率很低,一般仅用于删除某个临时取消的任务。
4. 所有实现都是线程安全的。
但是对于集合中的批量操作方法,如果其实现类没有特殊处理的话,那么addAll、containsAll、retainAll、removeAll等可能不会原子地执行。
5. 队列,整体上都基本准寻先进先出的访问顺序。
在整体上看,各个实现类是符合FIFO的顺序的。
主要实现类
LinkedBlockingQueue
:链表式阻塞队列ArrayBlockingQueue
:数组式阻塞队列PriorityBlockingQueue
:优先级阻塞队列LinkedBlockingDeque
:阻塞型双端队列DelayQueue
:延时阻塞队列SynchronousQueue
:实时同步队列(没有任何存储元素的空间)- …………
BlockingQueue方法的四类形式
BlockingQueue的所有实现类的方法都分为如下四类。相对于其他的集合操作方法,put和take是实现阻塞操作的核心方法,需要重点关注。
Throws exception
:操作未实现时(正常流程下的执行)抛出异常Special value
:根据操作的实际情况,返回特定值,例如null、falseBlocks
:阻塞当前线程,直到当前线程可以成功执行Times out
:尝试指定时间后,放弃执行
Throws exception | Special value | Blocks | Times out | |
新增 | add(E e) | offer(E e) | put(E e) | offer(E e, long timeout, TimeUnit unit) |
删除 | remove() | poll() | take() | poll(long timeout, TimeUnit unit) |
查询 | element() | peek() |
BlockingQueue类确定了阻塞队列的整体框架,确定了各个方法的定义,因此也是了解阻塞队列一定要学习的类。
本文中大部分都是从源码注释中解读而来,同时也包含了一些自己的理解,如果表述有误,还望指出。
AbstractQueue
概览
AbstractQueue类,提供了一些Queue操作的骨架实现。
这里提及AbstractQueue的原因是,阻塞队列的大多实现类都继承该类,可以说,这个抽象类,实现了BlockingQueue的大部分通用功能。比如add、remove失败时抛出异常等等,下面会一一提及。
源码解析
这个类基本上搭建起了一个阻塞队列Throws exception形式的框架,它实现了各个抛出异常的方法。
各个方法都比较简单,关键在于了解其具体的实现思路。这对了解各个阻塞队列的实现类很有帮助。
add
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
当队列空间足够时,将直接插入成功。offer方法由具体的子类实现。
如果offer插入元素成功,则add返回true ,否则将抛出IllegalStateException异常。
remove
public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
检索并删除队列的队首元素。
它与poll不同之处仅在于,如果此队列为空,它会抛出NoSuchElementException异常。
删除成功后,返回删除的元素。
element
public E element() {
E x = peek();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
仅获取队列的队首元素并返回结果,并不进行操作。
与peek不同之处在于,如果此队列为空,它会引发NoSuchElementException异常。
clear
与addAll
public void clear() {
while (poll() != null)
;
}
public boolean addAll(Collection<? extends E> c) {
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
遍历添加或删除所有元素,实现挺简单的,不过这里并没有进行单个操作出现异常时的处理。
总结
阻塞队列了解得也差不多了,之前只是简单的学习了如何使用阻塞队列的方法,这次也是打算来一个全面深入的学习吧。知其然知其所以然,对于程序员还是蛮重要的。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
相关文章