阻塞队列与普通的队列(LinkedList/ArrayList)相比,支持在向队列中添加元素时,队列的长度已满阻塞当前添加线程,直到队列未满或者等待超时;从队列中获取元素时,队列中元素为空 ,会将获取元素的线程阻塞,直到队列中存在元素 或者等待超时。
在JUC包中常用的阻塞队列包含ArrayBlockingQueue/LinkedBlockingQueue/LinkedBlockingDeque等,从结构来看都继承了AbstractQueue实现了BlockingQueue接口(LinkedBlockingDeque是双向阻塞队列,实现的是BlockingDeque接口),在BlockingQueue接口中定义了几个供子类实现的接口,可以分为3部分,puts操作、takes操作、其他操作。
puts操作
add(E e) : 添加成功返回true,失败抛IllegalStateException异常
offer(E e) : 成功返回true,如果此队列已满,则返回 false(如果添加了时间参数,且队列已满也会阻塞)
put(E e) :将元素插入此队列的尾部,如果该队列已满,则一直阻塞
takes操作
remove(Object o) :移除指定元素,成功返回true,失败返回false
poll() : 获取并移除此队列的头元素,若队列为空,则返回null(如果添加了时间参数,且队列中没有数据也会阻塞)
take():获取并移除此队列头元素,若没有元素则一直阻塞。
peek() :获取但不移除此队列的头;若队列为空,则返回null。
other操作
contains(Object o):队列中是否包含指定元素
drainTo(Collection super E> c):队列转化为集合
关于阻塞队列,我们主要看LinkedBlockingQueue与ArrayBlockingQueue.
ArrayBlockingQueue
ArrayBlockingQueue是基于数组的、有界的、遵循FIFO原则的阻塞队列,队列初始化时必须指定队列的长度。
这是一个经典的“有界缓冲区”,其中固定大小的数组包含由生产者插入并由消费者提取的元素。创建后,无法更改容量。此类支持用于排序等待生产者和消费者线程的可选公平策略。默认情况下,不保证此顺序。但是,将fairness设置为true构造的队列以FIFO顺序授予线程访问权限。公平性通常会降低吞吐量,但会降低可变性并避免饥饿。
结构
相关变量
final Object[] items; //一个数组,用来存放队列中的变量(队列的基础)
int count; //队列中元素的数量
int takeIndex; //下一次take、poll、remove、peek操作的下标值
int putIndex; //下次add、offer、put操作的下标值
构造函数
ArrayBlockingQueue提供了三个构造函数,在只传递初始化大小值时,默认使用的锁是非公平锁,对比三个不同的构造函数而言,真正初始化队列的构造方法是ArrayBlockingQueue(int capacity, boolean fair)方法,传入集合的构造方法会在调用该方法后将集合遍历存入队列中
public ArrayBlockingQueue(intcapacity) {this(capacity, false);
}public ArrayBlockingQueue(intcapacity, boolean fair) {if (capacity <= 0)throw newIllegalArgumentException();this.items = newObject[capacity];lock = newReentrantLock(fair);//使用同一个锁对象,此处是与LinkedBlockingQueue(使用两个不同的锁来控制添加,取出操作)不同的地方
notEmpty = lock.newCondition();
notFull= lock.newCondition();
}public ArrayBlockingQueue(int capacity, boolean fair, Collection extends E>c) {this(capacity, fair);
final ReentrantLocklock = this.lock;lock.lock(); //Lock only for visibility, not mutual exclusion
try{int i = 0;try{for(E e : c) {
checkNotNull(e);//向数组中添加数据
items[i++] =e;
}
}catch(ArrayIndexOutOfBoundsException ex) {throw newIllegalArgumentException();
}
count=i;//设置下次添加操作对应的数组下标值
putIndex = (i == capacity) ? 0: i;
}finally{lock.unlock();
}
}
offer/add操作
add本质上调用的是offer操作,通过返回值true/false可以判断队列中添加元素是否成功,队列已满返回false
publicboolean offer(E e) {
checkNotNull(e);
final ReentrantLocklock = this.lock;lock.lock();try{//队列已满,直接返回false
if (count ==items.length)return false;else{
e