java并发编程之美 学习笔记
ArrayBlockingQueue
总体结构
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
final Object[] items;
//下一个take元素index, 当takeIndex > items.length ,则从0重新开始
int takeIndex;
//下一个put元素index, 当putIndex> items.length ,则从0重新开始
int putIndex;
//元素实际个数,当take时--,put时++
int count;
final ReentrantLock lock;
private final Condition notEmpty;
private final Condition notFull;
}
构造函数
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
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 ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair);
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = 0;
try {
for (E e : c) {
//NPE
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
//更新count,这个操作在lock内部,是线程安全的
count = i;
//更新下一个put元素index
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
offer
向队尾添加元素,当元素为null时抛出NPE, 当队列已满,直接返回false,非阻塞
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
//队列已满 -- 直接返回false,不阻塞
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
private void enqueue(E x) {
final Object[] items = this.items;
items[putIndex] = x;
//添加完成之后,队列已满,则下一个put坐标为0
if (++putIndex == items.length)
putIndex = 0;
count++;
notEmpty.signal();
}
put
向队尾添加元素,当元素为null时抛出NPE, 当队列已满阻塞等待
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
//队列已满----阻塞等待,
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
poll
从队列头部获取并移除一个元素 ,如果队列为空则返回 null , 该方法是不阻塞的 。
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//1.出列
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
private E dequeue() {
//获取指定元素
E x = (E) items[takeIndex];
//设置为null
items[takeIndex] = null;
if (++takeIndex == items.length)
//重置takeIndex
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();
return x;
}
take
获取当前队列头部元素并从队列里面移除它。如果队列为空则阻塞等待
.
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
//队列为空 则阻塞等待
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
peek
获取队列头部元素但是不从队列里面移除它 , 如果队列为空则返回 null , 该方法是不
阻塞的。
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); //queue 为空时,返回null.
} finally {
lock.unlock();
}
}
final E itemAt(int i) {
return (E) items[i];
}
疑问
//出列元素时,重置
if (++takeIndex == items.length)
takeIndex = 0;
//入列元素 ,重置
if (++putIndex == items.length)
putIndex = 0;
可以用下图可以来帮助理解上述代码: