BlockingQueue是java的一个线程安全的阻塞队列的接口,
ArrayBlockingQueue 实现了 此接口,很简单,从名字上可以看出来,内部是 数组 实现的
ArrayBlockingQueue 源码中的部分变量:
final Object[] items; //存储所有元素的地方
int takeIndex; //获取元素的时候就是取出 takeIndex位置的元素
int putIndex; //添加元素根据 putIndex添加到指定位置
int count; //队列中的元素个数
final ReentrantLock lock;
/** ArrayBlockingQueue就是通过notEmpty和 notFull来实现阻塞功能的 */
private final Condition notEmpty;
private final Condition notFull;
transient Itrs itrs = null; //暂时不知道用来干嘛的
offer方法,用于往队列里面添加元素,
public boolean offer(E e) {
checkNotNull(e); //判断是否为null
final ReentrantLock lock = this.lock;
lock.lock();
try {
//如果队列已满,返回false
if (count == items.length)
return false;
else {
enqueue(e); //入 队
return true;
}
} finally {
lock.unlock();
}
}
enqueue方法:
private void enqueue(E x) {
final Object[] items = this.items;
items[putIndex] = x; //元素x放入 putIndex的位置
if (++putIndex == items.length) //先putIndex加一,再判断putIndex到达末尾,再从0开始
putIndex = 0;
count++;
notEmpty.signal(); //通知 正在 notEmpty上等待的线程,
}
put方法,若元素已满会一直等待
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await(); //等待,直到dequeue方法获取元素后调用notFull.signal()
enqueue(e);
} finally {
lock.unlock();
}
}
take方法,从队列获取元素,若没有,则等待
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await(); //没有元素就等待
return dequeue(); //出队
} finally {
lock.unlock();
}
}
dequeue方法
private E dequeue() {
final Object[] items = this.items;
E x = (E) items[takeIndex]; //获取takIndex位置的元素
items[takeIndex] = null; //将takeIndex的元素设置为null
if (++takeIndex == items.length) //先takeIndex加一,在判断是否等于数组长度
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal(); //唤醒正在等待 notFull的线程
return x;
}
ArrayBlockingQueue的方法不多,基本就2大类
一类是 获取元素,如 poll,, take,peek
一类是 添加元素,如 add ,offer,put
然后各自实现了不同的特性, 如 获取(取出)不到是 继续等待,还是返回false 还是抛出异常等
内部用 ReentrantLock 实现同步,
当添加元素时,通过 notFull阻塞, 直到 等待 dequeue方法调用,唤醒notFull的线程
同理, 当获取元素时, 通过 notEmpty阻塞, 等待 enqueue方法调用,唤醒notEmpty的线程
简单且实用