一.组织架构图
二.ArrayBlockingQueue构造方法解析
入队方法:
1.构造指定大小的有界队列,默认为非公平的
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
2.构造指定大小的有界队列,指定为公平或者非公平锁 默认false为非公平
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair); //初始化ReentrantLock重入锁,出队入队拥有这同一个锁
notEmpty = lock.newCondition(); //初始化非空等待队列
notFull = lock.newCondition(); //初始化非满等待队列
}
3.构造指定大小的有界队列,指定为公平或非公平锁,指定在初始化时加入一个集合
public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair); //调用构造方法2
final ReentrantLock lock = 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 new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
三.ArrayBlockingQueue方法详细解析
1.add(e)//队列未满时,返回true;队列满则抛出IllegalStateException(“Queue full”)异常——AbstractQueue
public boolean add(E e) {
if (offer(e)) //实际调用的是offer方法,下面会详细说明
return true;
else
throw new IllegalStateException("Queue full");
}
2.offer(e)//队列未满时,返回true;队列满时返回false。非阻塞立即返回。
public boolean offer(E e) {
checkNotNull(e); //检验非空方法,为空会抛NullPointerException异常
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false; //如果已经满了的话就会结束程序的执行
else {
enqueue(e); //添加数据的方法
return true;
}
} finally {
lock.unlock();
}
}
向队列中添加数据的方法enqueue()
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(); //唤醒非空等待队列中的线程
}
在这里有几个ArrayBlockingQueue成员变量。items即队列的数组引用,putIndex表示等待插入的数组下标位置。
当items[putIndex] = x将新元素插入队列中后,调用inc将数组下标向后移动,如果队列满则将putIndex置为0:
3.offer(e, time, unit)//设定等待的时间,如果在指定时间内还不能往队列中插入数据则返回false,插入成功返回true。
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)
return false; //超时没有添加数据就会返回false
nanos = notFull.awaitNanos(nanos);//队列满了再在规定时间内等待
}
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
4.put(e)//队列未满时,直接插入没有返回值;队列满时会阻塞等待,一直等到队列未满时再插入。
public void put(E e) throws InterruptedException {
checkNotNull(e); //同样是首先检查插入元素是否为空
final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); //这里并没有调用lock方法,而是调用了可被中断的lockInterruptibly,该方法可被线程中断返回,lock不能被中断返回。
try {
while (count == items.length)
notFull.await(); //当队列满时,使非满等待队列休眠
enqueue(e); // 此时表示队列非满,故插入元素,同时在该方法里唤醒非空等待队列
} finally {
lock.unlock();
}
}
出队方法:
5.remove()//队列不为空时,返回队首值并移除;队列为空时抛出NoSuchElementException()异常——AbstractQueue
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();
}
}
6.poll()//队列不为空时返回队首值并移除;队列为空时返回null。非阻塞立即返回。
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue(); //队列没有元素返回null,有的话用dequeue方法取出来
} finally {
lock.unlock();
}
}
dequeue()获取数据方法
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;
}
7.poll(time, unit)//设定等待的时间,如果在指定时间内队列还为空则返回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();
}
}
8.take(e)//队列不为空返回队首值并移除;当队列为空时会阻塞等待,一直等到队列不为空时再返回队首值。
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); //这里并没有调用lock方法,而是调用了可被中断的lockInterruptibly,该方法可被线程中断返回,lock不能被中断返回。
try {
while (count == 0) //队列元素为空
notEmpty.await(); //非空等待队列休眠
return dequeue(); //此时表示队列非空,故删除元素,同时在里唤醒非满等待队列
} finally {
lock.unlock();
}
}
9.size方法
可以看到ArrayBlockingQueue队列的size方法,是直接返回的count变量,它不像ConcurrentLinkedQueue,ConcurrentLinkedQueue的size则是每次会遍历这个队列,故ArrayBlockingQueue的size方法比ConcurrentLinkedQueue的size方法效率高。而且ConcurrentLinkedQueue的size方法并没有加锁!也就是说很有可能其size并不准确,这在它的注释中说明了ConcurrentLinkedQueue的size并没有多大的用处。
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
至此就完成了ArrayBlockingQueue有界阻塞队列的源码解析和主要方法的介绍。实际ArrayBlockingQueue就如同ArrayList内部通过数组结构存储数据。