BlockingQueue 是一个接口,继承自Queue,已知实现类有以下几种:
一、ArrayBlockingQueue 有数组结构组成的有界阻塞队列
1、构造方法
在ArrayBlockingQueue类中有下面的3个构造方法:
1.1、 ArrayBlockingQueue(int)
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
1.2、ArrayBlockingQueue(int, boolean)
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.3、ArrayBlockingQueue(int, boolean, Collection extends E>)
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();
}
}
ArrayBlockingQueue 默认情况下不能保证线程访问队列的公平性,所谓公平性是指严格按照线程等待的绝对时间顺序,即最先等待的线程能够最先访问到 ArrayBlockingQueue。而非公平性则是指访问 ArrayBlockingQueue 的顺序不是遵守严格的时间顺序,有可能存在,当 ArrayBlockingQueue 可以被访问时,长时间阻塞的线程依然无法访问到 ArrayBlockingQueue
通过上面的三个构造方法可以构造一个ArrayBlockingQueue的队列,在构造方法中初始化了实列变量,下面是一些实例变量。
/** 保存队列的元素数组 */
final Object[] items;
/**取出元素的位置 */
int takeIndex;
/** 添加元素的位置 */
int putIndex;
/**队列中元素的数量*/
int count;
/*
* Concurrency control uses the classic two-condition algorithm
* found in any textbook.
*/
/** 锁对象 */
final ReentrantLock lock;
/** 不空的信号 */
private final Condition notEmpty;
/** 不满的信号量 */
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;
2、队列的操作
2.1 add/peek
add/peek是一对互斥操作,add向队列放入元素,peek从队列取出元素;
2.1.1、add
public boolean add(E e) {
return super.add(e);
}
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
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();
}
}
2.1.2、peek
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); // 队列没有元素,返回null
} finally {
lock.unlock();
}
}
2.2、put/take
put/take是一对互斥的操作,put向队列种放入元素,take取出元素,其实现方式和add/peek不一样。
2.2.1、put()
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();
}
}
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();
}
2.2.2、take()
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return 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;
}
2.3、offer(E)/poll()
2.3.1 offer(E)
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();
}
}
2.3.2 poll()
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
2.4、 offer(E, long, TimeUnit) 和 poll(long, TimeUnit)
这两个方法是普通offer/poll方法的加强版,在队列满时指定了重试的时间,如果超过指定的时间后还是无法添加或取出则返回false。
2.4.1 offer(E, long, TimeUnit)
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;
nanos = notFull.awaitNanos(nanos);
}
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
2.4.2 poll(long, TimeUnit)
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();
}
}
3 比较
3.1 添加方法比较
序号 | 方法名 | 队列满时处理方式 | 方法返回值 |
---|---|---|---|
1 | add(E e) | 抛出“Queue full”异常 | boolean |
2 | offer(E e) | 返回false | boolean |
3 | put(E e) | 线程阻塞,直到中断或被唤醒 | void |
4 | offer(E e, long timeout, TimeUnit unit) | 在规定时间内重试,超过规定时间返回false | boolean |
3.2 取出方法比较
序号 | 方法名 | 队列满时处理方式 | 方法返回值 |
---|---|---|---|
1 | peek() | 返回null | E |
2 | poll() | 返回null | E |
3 | take() | 线程阻塞,指定中断或被唤醒 | E |
4 | poll(long timeout, TimeUnit unit) | 在规定时间内重试,超过规定时间返回null | E |