本节学习ArrayBlockingQueue的源码:
1.首先看类的定义
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable
可以看到类继承了AbstractQueue且实现了接口BlockingQueue
public abstract class AbstractQueue<E> extends AbstractCollection<E> implements Queue<E> { /** * 构造方法 */ protected AbstractQueue() { } /** * 添加元素,如果添加成功,则返回true,否则异常 */ public boolean add(E e) { if (offer(e)) return true; else throw new IllegalStateException("Queue full"); } /** * 移除元素,如果移除成功,返回被移除的元素,否则异常 */ public E remove() { E x = poll(); if (x != null) return x; else throw new NoSuchElementException(); } /** * 获取元素,如果获取到元素,则返回,否则异常 */ public E element() { E x = peek(); if (x != null) return x; else throw new NoSuchElementException(); } /** * 清空队列 */ public void clear() { while (poll() != null) ; } /** * 添加元素,如果添加成功,则返回true,否则返回false,或者异常 */ public boolean addAll(Collection<? extends E> c) { if (c == null) throw new NullPointerException(); if (c == this) throw new IllegalArgumentException(); boolean modified = false; for (E e : c) if (add(e)) modified = true; return modified; } }
2.类的变量信息
/** 使用数组保存队列元素 */ final Object[] items; /** 下一个去除或者移除的元素的下标位置 */ int takeIndex; /** 下一个添加的元素的下标位置 */ int putIndex; /** 队列中元素的个数 */ int count; /** 控制所有访问的重入锁 */ final ReentrantLock lock; /** 取出元素的条件 */ private final Condition notEmpty; /** 添加元素的条件 */ 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;
3.添加元素的四个方法:
3.1 add 调用的抽象队列中的添加方法,会抛异常
public boolean add(E e) { return super.add(e); }
3.2 offer如果队列满了,则直接返回false。
public boolean offer(E e) { checkNotNull(e);//元素判空,如果为空,则抛空指针异常 final ReentrantLock lock = this.lock; lock.lock(); try { if (count == items.length)//如果队列元素满了,则返回false return false; else { enqueue(e);//否则 return true; } } finally { lock.unlock(); } }
private void enqueue(E x) { // assert lock.getHoldCount() == 1; // assert items[putIndex] == null; final Object[] items = this.items; items[putIndex] = x;//设置putIndex下标元素为x if (++putIndex == items.length)//如果putIndex加1后的长度等于数组长度,则设置putIndex为0 putIndex = 0; count++;//数组元素个数+1 notEmpty.signal();//唤醒取元素条件 }
3.3 put 可以中断且如果队列元素满了,要进入等待状态。
public void put(E e) throws InterruptedException { checkNotNull(e);//非空校验 final ReentrantLock lock = this.lock; lock.lockInterruptibly();//可以中断的锁 try { while (count == items.length)//如果队列元素满了 notFull.await();//添加元素的条件等待 enqueue(e);//否则添加元素 } finally { lock.unlock(); } }
3.4 offer可终端,超时时间内可以阻塞等待,超时后如果队列还是满的,则返回false。
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) { if (nanos <= 0)//如果队列满了且超过等待时间,则返回false return false; nanos = notFull.awaitNanos(nanos);//否则添加元素的条件等待nanos时间 } enqueue(e); return true; } finally { lock.unlock(); } }
4.取元素的几个方法
4.1 poll 如果队列中没有元素,则返回null
扫描二维码关注公众号,回复:
1559448 查看本文章
public E poll() { final ReentrantLock lock = this.lock; lock.lock(); try { return (count == 0) ? null : dequeue(); } finally { lock.unlock(); } }
private E dequeue() { // assert lock.getHoldCount() == 1; // assert items[takeIndex] != null; final Object[] items = this.items; @SuppressWarnings("unchecked") E x = (E) items[takeIndex]; items[takeIndex] = null;//设置元素为null if (++takeIndex == items.length) takeIndex = 0; count--; if (itrs != null) itrs.elementDequeued(); notFull.signal();//添加元素的条件唤醒 return x; }4.2 take 可中断,如果队列为空,则进入等待。
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0)//如果没有可移除的元素,则移除元素的条件等待 notEmpty.await(); return dequeue();//移除元素 } finally { lock.unlock(); } }
4.3 poll 可中断,如果队列为空,在等待时间内会进入等待状态,过了等待时间返回null。
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 dequeue(); } finally { lock.unlock(); } }
4.4 remove
public boolean remove(Object o) { if (o == null) return false; final Object[] items = this.items; final ReentrantLock lock = this.lock; lock.lock(); try { if (count > 0) {//如果队列不为空 final int putIndex = this.putIndex; int i = takeIndex; do { if (o.equals(items[i])) { removeAt(i); 移除元素 return true; } if (++i == items.length) i = 0; } while (i != putIndex); } return false; } finally { lock.unlock(); } }
void removeAt(final int removeIndex) { // assert lock.getHoldCount() == 1; // assert items[removeIndex] != null; // assert removeIndex >= 0 && removeIndex < items.length; final Object[] items = this.items; if (removeIndex == takeIndex) { // removing front item; just advance items[takeIndex] = null; if (++takeIndex == items.length) takeIndex = 0; count--; if (itrs != null) itrs.elementDequeued(); } else { // an "interior" remove // slide over all others up through putIndex. final int putIndex = this.putIndex; for (int i = removeIndex;;) { int next = i + 1; if (next == items.length) next = 0; if (next != putIndex) { items[i] = items[next]; i = next; } else { items[i] = null; this.putIndex = i; break; } } count--; if (itrs != null) itrs.removedAt(removeIndex); } notFull.signal(); }
5 其他方法
5.1 peek 返回下个要移除的元素值。
public E peek() { final ReentrantLock lock = this.lock; lock.lock(); try { return itemAt(takeIndex); // null when queue is empty } finally { lock.unlock(); } }
5.2 size 返回队列元素的个数
public int size() { final ReentrantLock lock = this.lock; lock.lock(); try { return count; } finally { lock.unlock(); } }
5.3 remainingCapacity 返回队列剩余的空间
public int remainingCapacity() { final ReentrantLock lock = this.lock; lock.lock(); try { return items.length - count; } finally { lock.unlock(); } }
5.4 contains判断队列中是否包含元素o
public boolean contains(Object o) { if (o == null) return false; final Object[] items = this.items; final ReentrantLock lock = this.lock; lock.lock(); try { if (count > 0) { final int putIndex = this.putIndex; int i = takeIndex; do { if (o.equals(items[i])) return true; if (++i == items.length) i = 0; } while (i != putIndex); } return false; } finally { lock.unlock(); } }
5.5 clear 清空队列,且唤醒所有添加数据的条件
public void clear() { final Object[] items = this.items; final ReentrantLock lock = this.lock; lock.lock(); try { int k = count; if (k > 0) { final int putIndex = this.putIndex; int i = takeIndex; do { items[i] = null; if (++i == items.length) i = 0; } while (i != putIndex); takeIndex = putIndex; count = 0; if (itrs != null) itrs.queueIsEmpty(); for (; k > 0 && lock.hasWaiters(notFull); k--) notFull.signal(); } } finally { lock.unlock(); } }
总结:
有界阻塞队列,底层数据结构是数组。
同步控制使用的重入锁和condition。