类介绍
类定位
首先BlockingQueue
直白的翻译过来就是阻塞队列,很容易联想到这是个和并发编程有关系的队列。最直白想象到的是在学操作系统的生产者——消费者和死锁相关的问题。
类继承关系分析
BlockingQueue
继承于Queue
。所以大概的情况如下所示:
![](https://img.haomeiwen.com/i3821632/9b88872937ce5651.png)
因为比较懒,所以直接从idea中截图了。
类使用场景
这个类的主要使用场景就是多线程情况下的队列处理了。比如消息队列等等。这里放一个示例代码,是直接从jdk注解中复制出来的,代码思路是多个线程往里放东西取东西。
class Producer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) {
queue = q;
}
public void run() {
try {
while (true) {
queue.put(produce());
}
} catch (InterruptedException ex) { ...handle ...}
}
Object produce() { ...}
}
class Consumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) {
queue = q;
}
public void run() {
try {
while (true) {
consume(queue.take());
}
} catch (InterruptedException ex) { ...handle ...}
}
void consume(Object x) { ...}
}
class Setup {
void main() {
BlockingQueue q = new SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}}
类注意事项
注意事项如下:
-
BlockingQueue
是Queue
的一个子类,所以Queue
的限制它都有,比如:- 不一定是FIFO,可以自己设置排序顺序
- 不允许有
null
-
BlockingQueue
是线程安全的,所以他的实现类不应该只把BlockingQueue
自己的方法做成线程安全的,他继承的Collection
,Queue
的方法要全弄成线程安全的
源码解析
方法归类
我们将源码进行归类讲解,BlockingQueue
对进队、出队、取队头三种方法有四种实现方式,我们列表如下:
Method | Throws exception | Special value | Blocks | Times out |
---|---|---|---|---|
Insert | add(e) | offer(e) | put(e) | offer(e, time, unit) |
Remove | remove() | poll() | take() | poll(time, unit) |
Examine | element() | peek() | not applicable | not applicable |
注意:
- 我们将方法分成四类主要是依据当前队列的情况不允许立即入队/出队/取队头时,方法的操作。我们的不允许立即操作指的是队列满了不能入队或者队列空了不能出队,不是原子操作或者上锁引起的等待
- 四种方法,不能立即操作时会有不同的表现:比如抛异常、返回特殊值、阻塞等待、限时阻塞等待。
抛异常
boolean add(E e);
会抛异常
boolean remove(Object o);
E element();
返回特殊值
boolean offer(E e);
不合理入参也会抛异常
E poll();
E peek();
阻塞等待
void put(E e) throws InterruptedException;
入队列
E take() throws InterruptedException;
取队头
限时阻塞
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;
E poll(long timeout, TimeUnit unit) throws InterruptedException;
新功能的方法
int drainTo(Collection<? super E> c);
将此BlockingQueue
中的元素剪切至目标Collection
。
注意:
- 此方法线程安全
- 如果方法执行时挂了,元素可能在
this
/C
/no Where
。所以挂了的话还是挺难搞的 - 在剪切过程中如果
C
出现了改变,会引起剪切失败 - 此方法效率比循环调用出队操作要高
int drainTo(Collection<? super E> c, int maxElements);
有个数量限制。
网友评论