BlockingQueue,什么鬼,刚开始接触到这个数据结构的时候,从字面意义上根本没看出这个的意思,怎么会有个block冠在前边,感觉是个不太好的词。但是又发现其在某些服务任务框架上经常使用。今天我们来探秘下这个数据结构的用法。
BlockingQueue源码分析
首先,打开JDK的源码,找到BlockingQueue这个数据结构。(android开发要安装的jdk 1.8,在其安装目录即有源码)。
package java.util.concurrent;
import java.util.Collection;
import java.util.Queue;
* @since 1.5
* @author Doug Lea
* @param <E> the type of elements held in this collection
*/
public interface BlockingQueue<E> extends Queue<E> {
首先,一个数据结构,包名是java.util.concurrent,很显然,这是java为并发操作设计的数据结构。并且还import了Collection和Queue。 所以其当然也有这两个数据结构的特性。而BlockingQueue是个interface接口类型,那这就不是一个真实的可以对象化的类。如同List 是ArrayList<>()的父类,我们初始化时经常用new ArrayList<>()创建对象并赋值给List<>类型的变量一样。他们都是泛型类,数据类型E可以在使用时具体制定。
接下来我们分析这个接口的主要方法。
/**
* Inserts the specified element into this queue if it is possible to do
* so immediately without violating capacity restrictions, returning
* {@code true} upon success and throwing an
* {@code IllegalStateException} if no space is currently available.
* ……
* /
boolean add(E e);
从注释看出,add方法可以插入数据到队列中,如果队列满了,则抛出IllegalStateException异常。
之后的方法是offer(E e),其和add方法的不同之处在于,前者在队列满时是异常,后者是返回false,而add只是抛出异常。
而下一个方法,就可以看出BlockingQueue的精髓所在,即阻塞。
/**
* Inserts the specified element into this queue, waiting if necessary
* for space to become available.
*
* @param e the element to add
* @throws InterruptedException if interrupted while waiting
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this queue
* @throws NullPointerException if the specified element is null
* @throws IllegalArgumentException if some property of the specified
* element prevents it from being added to this queue
*/
void put(E e) throws InterruptedException;
put的精髓就在于,当队列满的时候,会阻塞住,等有空间时插入。
/**
* Retrieves and removes the head of this queue, waiting if necessary
* until an element becomes available.
*
* @return the head of this queue
* @throws InterruptedException if interrupted while waiting
*/
E take() throws InterruptedException;
反之, 队列的取元素也有阻塞方法,如果队列中有元素,则取出处理,否则队列为空时则阻塞等待。
这里只看了上述方法的注释,其他的都是些辅助方法。
由于BlockingQueue只是个接口,只有定义的方法,但是没有实际的实现,即如何实现阻塞,是在实现类中实现的。
其实现类有ArrayBlockingQueue、BlockingDeque等,详细的如下图所示。
ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
我们分别分析ArrayBlockingQueue和BlockingDeque的源码。
ArrayBlockingQueue源码分析
这里不会分析所有的方法,只捡重要的变量和方法进行分析。
首先是类的声明和变量。
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
/** The queued items */
final Object[] items;
/** items index for next take, poll, peek or remove */
int takeIndex;
/** items index for next put, offer, or add */
int putIndex;
/** Number of elements in the queue */
int count;
/** Main lock guarding all access */
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
/**
* Shared state for currently active iterators, or null if there
* are known not to be any. Allows queue operations to update
* iterator state.
*/
transient Itrs itrs = null;
其中的items数组,即要添加的队列数据,有取数据的takeIndex和添加数据的putIndex。还有可重入锁lock。
其构造函数显示,队列的长度是外部传入的,即这个类的对象创建的时候,其大小就确定了。同时确定了lock为非公平锁。
/**
* Cre