JUC包下定义了一个接口:BlockingQueue。其实现类有ArrayBlockingQueue等。本文先来介绍一下ArrayBlockingQueue。从字面可以看出,ArrayBlockingQueue是一种基于数组的阻塞队列,阻塞队列在线程池中会经常使用到。
首先来看看ArrayBlockingQueue的类图,如下所示。从类图可以看出,ArrayBlockingQueue继承自AbstractQueue,实现了BlockingQueue接口。
在ArrayBlockingQueue内部有一个数组items,同时定义了takeIndex和putIndex变量。由于是队列,因此一端入队操作,另一端进行出队操作。另外,内部定义了ReentrantLock作为独占锁。
1、构造函数
先来看看其构造函数。其有三给构造函数,不过都是调用这个构造函数。
构造函数的参数需要指定初始容量,同时指定采用公平锁还是非公平锁。从这一点可以看出,ArrayBlockingQueue是一个有界队列。
2、offer函数
offer操作用于向队列尾部插入一个元素,如果空闲则插入元素,如果非空闲,返回true。如果队列满,则返回false。下面让我们来看看offer操作的源码。
从上面的源码可以看出,不管插入成功与否,都会立即返回结果,因此这个方法是非阻塞的,但是也不能保证一定插入元素成功。
3、put函数
从源码中可以看出,put操作首先检查元素是否位空,如果为空,则抛异常。然后进行加锁,然后判断当前队列是否满了,如果满了就阻塞当前线程,然后挂起放入条件队列。当然,这个方式是相应中断的(因为上面lockInterruptibly方法可以响应中断)。如果队列没满,则入队。最后释放锁。
4、poll操作
poll是从队列头部取走元素,其源码如下:
首先进行加锁操作,然后判断当前队列元素是否为0,如果是返回空。否则返回队列头元素。这个方法是不支持响应中断的。至于deque操作,就是去数组中取元素,和普通队列处理逻辑没有区别。
5、take操作
take操作也是从队列头取元素。其源码如下所示:
从源码上可以看出,take也是支持响应中断的。如果队列元素为空,则会阻塞挂起,除非队列有元素被唤醒。也就是这个方法一定要保证取到元素,如果取不到元素,会等到有元素才返回。不像上面的poll方法,取不到就返回null。
6、peek操作
peek操作时查看队列首部的元素,但是不移除。源码如下:
从源码上可以看出,此方法也是非阻塞的。即使队列没有元素也就是会立即返回的(返回null)。不像上面的take操作,没有元素就等到有元素再返回。
7、size操作
此方法是获取队列元素个数的方法,源码如下:
从源码可以看出,size操作时加锁的,因为在定义count变量的时候没有使用volitate修饰,这样通过加锁保证了内存的可见性。这里其实也可以通过putIndex和takeIndex来得到队列元素长度。在Netty框架中的Bytebuf就是这样计算的。