/** The queued items */
存储元素的数组
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;
/** Main lock guarding all access */
存储和获取元素时需要加锁
final ReentrantLock lock;
/** Condition for waiting takes */
队列中放入元素后,通知等待获取元素的线程
private final Condition notEmpty;
/** Condition for waiting puts */
队列中取出元素后,通知等待放入元素的线程
private final Condition notFull;
构造函数
初始化时会创建锁,默认是非公平锁
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();
}
插入元素方法:
1.add
add方法调用的是offer方法,如果插入元素失败,会抛出异常
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
2.offer
先加锁,再判断队列是否满了,满了返回false,不满就调用enqueue方法,插入元素,最后释放锁
public boolean offer(E e) {
Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
插入元素时会调用notEmpty.signal方法,唤醒等待获取元素的线程
private void enqueue(E e) {
final Object[] items = this.items;
items[putIndex] = e;
if (++putIndex == items.length) putIndex = 0;
count++;
notEmpty.signal();
}
3.put(具有阻塞功能)
通过while循环判断队列是否满了,满了就挂起线程,阻塞等待唤醒
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();
}
}
取出元素
1.peek
取出元素先加锁,再根据下标取出元素,最后释放锁
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
final E itemAt(int i) {
return (E) items[i];
}
2.poll
取元素前先加锁,判断当前队列是否为空,不为空则取出元素,为空则返回null,最后释放锁
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private E dequeue() {
final Object[] items = this.items;
E e = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length) takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();
return e;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void elementDequeued() {
//队列为空时,会调用该方法
if (count == 0)
queueIsEmpty();
else if (takeIndex == 0)
takeIndexWrapped();
}
3.take
队列为空时,会挂起线程
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}