一、 简介
BlockingQueue简介
- 首先它一个队列,所以它继承了Queue接口具有队列的特性;
- 其次是一个阻塞队列。
我们平时常用的队列只要为一下两种
- 先进先出-FIFO:先插入的数据最先出队列,类似我们排队买东西,先排队的先买
- 先进后出-LIFO:后插入的数据最先出队列,类似我们放羽毛球的球筒,先放进去的最后才能拿出来
队列不只有这两种,实现方式不同则会衍生出不同的队列
我们先来看下BlockingQueue的基本数据结构, 如下图
在多线程环境下,我们可以通过BlockingQueue来实现不同线程间的数据共享,比如生产者–消费者模式,我们可以让若干线程生产数据,若干线程消费数据,理想状态下是没有问题的,但是当生产速度大于消费速度导致数据有了一定的积累,或者消费速度大于生产速度导致数据都消费完毕,这种情况下就需要特殊处理下,当数据积累到一定数量时 生产者需要阻塞等待,直到有消费者消费数据,反之亦然。
概括下就是以下两个结论
- 队列空了:所有的消费线程阻塞等待,直到生产者生产数据放入队列,同时唤醒消费线程
- 队列满了:所有的生产线程阻塞等待,直到消费者消费了队列中的数据,同时唤醒生产者
当然这些BlockingQueue都已经帮我们做了,我们不需要在关注这些
二、BlockingQueue核心方法
// 添加指定数据到队尾,成功返回true, 失败抛出IllegalStateException异常
// 底层调用的offer
boolean add(E e);
// 添加指定数据到队尾,成功返回true, 失败返回 false
boolean offer(E e);
// 添加指定数据到队尾,如果队列满了,则阻塞当前线程,直到抛出InterruptedException异常
void put(E e) throws InterruptedException;
// 添加指定数据到队列,如果队列满了则等待指定时间,成功返回true, 失败返回 fals
// 如果在等待时间内中断了等待线程,则抛出InterruptedExcepution
boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException;
// 取出队列的头部的元素,如果没有元素则一直等待直到成功
// 等到过程中断线程则抛出InterruptedExcepution
E take() throws InterruptedException;
// 取出队列的头部的元素,如果没有元素则等待指定时间直到成功,获取不到返回null
// 等到过程中断线程则抛出InterruptedExcepution
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
// 获取当前队列剩余容量
int remainingCapacity();
// 删除队列中的元素
boolean remove(Object o);
// 是否保存元素
public boolean contains(Object o);
// 将队列中全部元素移动到指定集合
int drainTo(Collection<? super E> c);
// 将队列中指定数量元素移动到指定集合
int drainTo(Collection<? super E> c, int maxElements);
BlockingQueue和JDK的Queue接口是兼容的,同时在其基础上添加了阻塞的功能。
我们可以看到添加有三个方法,那么它们有什么区别?返回值我们可以看出 **add()和offer()**返回的是boolean,put()则无返回值会抛出InterruptedExcepution中断异常,所以add()和offer()是非阻塞的,put()是阻塞的。
同理,在获取数据的时候我们可以看到take()和poll()也都抛出了InterruptedExcepution中断异常,所以我你推断出这两个方法也是阻塞的。
三、具体实现
刚才我们已经介绍了BlockingQueue的核心方法,下面让我们看下它有哪些常用的具体实现吧
如下图所示,接下来我会一一来介绍他们的特性和具体实现
1、ArrayBlockingQueue
BlockingQueue之ArrayBlockingQueue
2、LinkedBlockingQueue
BlockingQueue之LinkedBlockingQueue
四、比较
ArrayBlockingQueue和LinkedBockingQueue比较
-
底层数据结构不同:ArrayBlockingQueue底层是循环数组,LinkedBlockingQueue底层是单项链表
-
初始化方式不同:ArrayBlockingQueue必须制定大小初始化;LinkedBlockingQueue可以不指定容量初始化,默认大小Integer.MAX_VALUE
-
阻塞方式不同:ArrayBlockingQueue是通用一个全局锁来处理所有操作,入队和出队不能同步;LinkedBlockingQueue队头和队尾分别使用了锁,入队和出队可一同步进行