前言
从这章开始我们就正式的进入到了BolckingQueue的篇章
正文
类的描述
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, Serializable
通过数组实现的一个有界blockingQueue。这个队列的命令元素的FIFO(先进先出)。队列的头是已在队列中的元素,是最长的时间。队列的尾部是已在队列中的元素最短的时间。新的元素插入在队列的尾部,并在队列的头部获取元素的队列检索操作。
这是一个经典的“有界缓冲区”,其中一个固定大小的数组保存生产者插入的元素和消费者提取的元素。一旦创建,容量就无法更改。尝试将元素放入完整队列将导致操作阻塞;尝试从空队列中获取元素也会被阻塞。
此类支持一个可选的公平策略,用于排序等待的生产者线程和消费者线程。默认情况下,不保证此顺序。然而,公平性设置为true的队列以FIFO顺序授予线程访问权限。公平性通常会降低吞吐量,但会降低可变性并避免饥饿。
这个类和它的迭代器实现所有的可选方法的Collection和Iterator接口。
常量、变量、静态内部类
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;
/*
* Concurrency control uses the classic two-condition algorithm
* found in any textbook.
*/
/** Main lock guarding all access */
final ReentrantLock lock;
/** tasks的条件*/
private final Condition notEmpty;
/** put的条件 */
private final Condition notFull;
/**
* Shared state for currently active iterators, or null if there
* are known not to be any. Allows queue operations to update
* iterator state.
*/
transient Itrs itrs = null;
通过上面变量,和类的描, 猜测是通过items数组存储元素的,通过ReentrantLock来实现阻塞的
构造方法
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
// fair ReentranLock是否是公平锁
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(); // 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();
}
}
队列中常用的方法
add
public boolean add(E e) {
return super.add(e); //父类的add
}
//abstractQueue
public boolean add(E e) {
if (offer(e)) //调用的offer
return true;
else
throw new IllegalStateException("Queue full");
}
offer
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length) //超出了队列初始化的长度
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
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(); //task从等待队列中移到同步队列,具体放到lock中学习
}
remove
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();
}
}
void removeAt(final int removeIndex) {
// assert lock.getHoldCount() == 1;
// assert items[removeIndex] != null;
// assert removeIndex >= 0 && removeIndex < items.length;
final Object[] items = this.items;
if (removeIndex == takeIndex) {
// removing front item; just advance
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
} else {
// an "interior" remove
// slide over all others up through putIndex.
//通过putIndex相上移动元素
final int putIndex = this.putIndex;
for (int i = removeIndex;;) {
int next = i + 1;
if (next == items.length)
next = 0;
if (next != putIndex) {
items[i] = items[next];
i = next;
} else {
items[i] = null;
this.putIndex = i;
break;
}
}
count--;
if (itrs != null)
itrs.removedAt(removeIndex);
}
notFull.signal();
}
//AbstractQueueRemove
public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
poll
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
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;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();
return x;
}
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];
}
element
public E element() {
E x = peek(); //调用的peek
if (x != null)
return x;
else
throw new NoSuchElementException();
}
结论:
根据上面的方法,发现一个很有意识的东西,虽然存储元素是用的item数组,但是先进先出的规则是用的putIndex和taskIndex来实现的,新添加一条数据, putIndex +1 , 新移除一条数据 taskIndex + 1 当 putIndex == item.lenth 时, putIndex =0,从数组的第一个元素算起,taskIndex同理,这样其实数据结构就是一个环的形状
有兴趣的同学可以通过这段代码来操作下
public class ArrayBlockingQueueDemo {
public static void main(String[] args) {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(3); // putIndex = 0 taskIndex = 0
arrayBlockingQueue.add("AAA"); // putIndex = 1 taskIndex = 0
arrayBlockingQueue.add("BBB"); // putIndex = 2 taskIndex = 0
arrayBlockingQueue.add("CCC"); // putIndex = 0 taskIndex = 0
arrayBlockingQueue.remove(); // putIndex = 0 taskIndex = 1
arrayBlockingQueue.add("DDD"); // putIndex = 1 taskIndex = 1
}
}
当走完最后一步的时候,item里面的数据存储, ”DDD“ 在 item 0的位置,所以把他形容成环
1. ArrayBlockingQueue 是一个有界队列
2. 通过数组来保存数据,但是通过taskIndex和putIndex来控制先进先出,数据结构实际是一个环
3, 通过ReentrantLock来实现的阻塞和线程安全