一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部 是在队列中存在时间最长的元素。队列的尾部 是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列检索操作则是从队列头部开始获得元素。
这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致放入操作受阻塞;试图从空队列中检索元素将导致类似阻塞。
此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”
/** The queued items 顾名思义,array的底层使用数组实现的*/
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;
然后是全局锁和两个condition
/** Main lock guarding all access */
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
下面针对几个略微复杂的方法进行跟读
通过构造器可以看出来这个队列的公平是通过锁Lock来实现的
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
看一下他的添加方法
public boolean add(E e) {
return super.add(e);//调用父类AbstractQueue
}
父类AbstractQueue
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
这里的offer是由于implements Queue,但是接口本身是并没有实现的,而是通过反转的方式将实现交给了子类ArrayBlockingQueue的offer来实现.有些绕但是明白jvm的机制还是可以理解的,最终jvm类加载先记录父类方法的地址,(可以想象成将父类的方法先放进来)然后加载子类,如果有相同的就覆盖,不同的就填充.所以只要子类里面有的方法不论父类有没有都会执行子类的.但是利用这么一个接口抽象过度多少有点坑,瞬间怀念spring源码里面的写法,在父类写个抽象方法,然后交给子类实现,可读性好点.
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
insert(e);
return true;
}
} finally {
lock.unlock();
}
}
private void insert(E x) {
items[putIndex] = x;
putIndex = inc(putIndex);
++count;
notEmpty.signal();
}
final int inc(int i) {
return (++i == items.length) ? 0 : i;//让位置移动1
}
//以下是等待插入,将内容放入condition寄存 当收到singnal唤醒的时候就启动
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
insert(e);
} finally {
lock.unlock();
}
}
剩余部分的代码基本相同,就不一一分析了