这一系列主要聚焦BlockingQueue的实现类,称之为阻塞队列,到底代表什么含义,我们不打算从注释出发,从实现类出发,第一个分析ArrayBlockingQueue。
从构造方法出发。
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
//是公平锁还是非公平锁。
lock = new ReentrantLock(fair);
//从这里看其实是一个生产者消费者模型了。这里不展开讲Condition原理了,只需要知道
//锁住 用Condtion.await()。释放锁用的是condition.signal();
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
还是从offer出发吧。因为add里面调用的也是add,只不过add会抛出异常,offer不会异常只会返回false。
public boolean offer(E e) {
Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
//锁住。这个时候如果别的线程再想offer只能等待了。
lock.lock();
try {
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
再比较下put方法。
public void put(E e) throws InterruptedException {
Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
这个方法跟offer方法别无二致,就是如果满的情况会阻塞。
//很简单往队列添加E,如果添加成功那么释放notEmpty锁。
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length) putIndex = 0;
count++;
notEmpty.signal();
}
//看下poll方法。
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
可以类比take方法也会阻塞,如果为空。
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;
//如果takeIndex 位置等于数组大小。那么从0开始take。
if (++takeIndex == items.length) takeIndex = 0;
//队列数量减少。
count--;
if (itrs != null)
itrs.elementDequeued();
//队列未满的锁释放了。
notFull.signal();
return x;
}
到这里可以关注到实际上是一个生产者消费者模型。这个队列是有固定容器大小的。