ArrayBlockingQueue是一个基于数组实现的有界的阻塞队列。
属性
//底层存储元素的数组。为final说明一旦初始化,容量不可变,所以是有界的。 final Object[] items; //下一个take, poll, peek or remove操作的index位置 int takeIndex; //下一个put, offer, or add操作的index位置 int putIndex; // 元素数量 int count; /** * 用于并发控制:使用经典的双Condition算法 */ final ReentrantLock lock; /** 获取操作等待条件 */ private final Condition notEmpty; /** 插入操作等待条件 */ private final Condition notFull;
添加操作
1.add操作(不常用)
add()是最原始的方法。当队列满时,会抛出IllegalStateException。
public boolean add(E e) { return super.add(e); } // 父类AbstractQueue中的add() public boolean add(E e) { if (offer(e)) return true; else throw new IllegalStateException("Queue full"); }
2.offer操作
offer有两个版本。
不带超时版本:队列满时,直接返回false。
带超时版本:队列满时,阻塞直到队列可用。
public boolean offer(E e) { checkNotNull(e); final ReentrantLock lock = this.lock; lock.lock(); try { //队列已满,直接返回false if (count == items.length) return false; else {//未满,则插入元素 insert(e); return true; } } finally { lock.unlock(); } } /**offer,带超时版本**/ public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { checkNotNull(e); long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; //可中断加锁 lock.lockInterruptibly(); try { //不停判断是否满了 while (count == items.length) { //超时,则直接返回false if (nanos <= 0) return false; //队列已满,则等待 nanos = notFull.awaitNanos(nanos); } //阻塞直到队列可用,则插入元素 insert(e); return true; } finally { lock.unlock(); } }
3.put操作
public void put(E e) throws InterruptedException { //检查参数是否为null。为null则抛异常 checkNotNull(e); final ReentrantLock lock = this.lock; //加锁。可中断 lock.lockInterruptibly(); try { //队列已满则一直等待,直到队列有可用空间 while (count == items.length) notFull.await();//等待 //队列空闲时,插入元素 insert(e); } finally { //释放锁 lock.unlock(); } }
删除操作
1.poll操作
public E poll() { final ReentrantLock lock = this.lock; lock.lock(); try { return (count == 0) ? null : extract(); } finally { lock.unlock(); } } private E extract() { final Object[] items = this.items; E x = this.<E>cast(items[takeIndex]);//强转 //删除 items[takeIndex] = null; takeIndex = inc(takeIndex); --count; //通知 notFull.signal(); return x; } /**poll,带超时版本**/ public E poll(long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0) { if (nanos <= 0) return null; nanos = notEmpty.awaitNanos(nanos); } return extract(); } finally { lock.unlock(); } }
2.take操作
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0) notEmpty.await(); return extract(); } finally { lock.unlock(); } }
3.peek操作
public E peek() { final ReentrantLock lock = this.lock; lock.lock(); try { return (count == 0) ? null : itemAt(takeIndex); } finally { lock.unlock(); } }
清空操作
public void clear() { final Object[] items = this.items; final ReentrantLock lock = this.lock; lock.lock(); try { //依次将所有元素设为null for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) items[i] = null; //count,putIndex,takeIndex都为0 count = 0; putIndex = 0; takeIndex = 0; notFull.signalAll(); } finally { lock.unlock(); } }
总结
BlockingQueue接口提供了3个添加元素方法。
- add:添加元素到队列里,添加成功返回true,如果队列已满则抛出IllegalStateException异常。不常用。
- offer:添加元素到队列里,添加成功返回true,如果队列已满添加失败,返回false
- put:添加元素到队列里,添加成功返回true,如果队列已满则阻塞直到队列可用
同时,BlockingQueue接口提供了3个获取(并删除)元素的方法。
- remove:
- poll:返回队列头部元素。队列为空时,返回null
- take:队列为空时,会阻塞直到有数据加入到队列中