一 类继承图
二 ArrayBlockingQueue
2.1 属性
//数组存储对象
final Object[] items;
//取出队数据的索引
int takeIndex;
//入队数据的存储索引
int putIndex;
//队列元素数量
int count;
//并发控制
final ReentrantLock lock;
//lock的条件对象,take()时若队列为空,则等待该条件对象
private final Condition notEmpty;
//lock的条件对象,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;
2.2 实例化
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) {//不可超多配置的queue容量
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;//更新入队索引,达到数组长度则从0开始
} finally {
lock.unlock();
}
}
2.3 入队
- offer(),成功返回true,失败返回false
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)//更新入队索引,达到存储数组长度则修改为0
putIndex = 0;
count++;
notEmpty.signal();//通知调用take(),因无队列数据休眠等待获取出队数据的线程唤醒。
}
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");
}
- put()成功返回true,队列存储已满,则等待条件对象notFull通知
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();
}
}
- 存储队列满时,指定等待超时时间。超时后仍无空间,返回false。成功返回true
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)//超时后仍无空间,返回false
return false;
//指定超时时间休眠等待
nanos = notFull.awaitNanos(nanos);
}
enqueue(e);//入队
return true;
} finally {
lock.unlock();
}
}
2.4 获取出队数据
- poll(),无数据返回null,有数据则获取出队数据
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];//获取当前takeIndex的数据
items[takeIndex] = null;//清空引用
if (++takeIndex == items.length)//下一出队数据索引+1,达到长度则循环赋值为0
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();//通知休眠等待入队的put(),线程唤醒获取锁后,执行入队操作。
return x;
}
public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
-
poll(long timeout, TimeUnit unit)
获取出队数据,若无数据则按参数休眠指定时间。超时仍无数据则返回null
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();
}
}
2.5 其他
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);//删除后,需要后面数据前移一位。若刚好为下一出队数据,则修改出队数据索引takeIndex+1。
return true;
}
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
return false;
} finally {
lock.unlock();
}
}
public Object[] toArray() {
Object[] a;
final ReentrantLock lock = this.lock;
lock.lock();
try {
final int count = this.count;
a = new Object[count];
int n = items.length - takeIndex;
if (count <= n)//数据连续分布在数据中,直接拷贝
System.arraycopy(items, takeIndex, a, 0, count);
else {//数据分布在数组两端,则分别拷贝到新数组中
System.arraycopy(items, takeIndex, a, 0, n);
System.arraycopy(items, 0, a, n, count - n);
}
} finally {
lock.unlock();
}
return a;
}
三 LinkedBlockingQueue
3.1 属性
static class Node {
E item;
Node next;
Node(E x) { item = x; }
}
//头尾指针
transient Node head;
private transient Node last;
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();
3.2 入队/出队
- 通知对应的条件对象,通知时需要加锁,所以调用通知函数前必须先释放入队出队的锁。避免死锁
/**
* Signals a waiting take. Called only from put/offer (which do not
* otherwise ordinarily lock takeLock.)
*/
private void signalNotEmpty() {
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
notEmpty.signal();
} finally {
takeLock.unlock();
}
}
/**
* Signals a waiting put. Called only from take/poll.
*/
private void signalNotFull() {
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
notFull.signal();
} finally {
putLock.unlock();
}
}
- 入队出队基本流程和ArrayBlockingQueue一致,只是因使用两个锁,所以为避免死锁,通知条件对象的调用需要在释放锁之后执行。以put()代码为例:
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
Node node = new Node(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)//释放入队锁之后,再通知notEmpty
signalNotEmpty();
}
四 LinkedBlockingDeque
/** Doubly-linked list node class */
static final class Node {
E item;
Node prev;
Node next;
Node(E x) {
item = x;
}
}
/** Main lock guarding all access */
final ReentrantLock lock = new ReentrantLock();
/** Condition for waiting takes */
private final Condition notEmpty = lock.newCondition();
/** Condition for waiting puts */
private final Condition notFull = lock.newCondition();
- 入队,外部调用入队的逻辑和ArrayBlockingQueue一致
/**
* Links node as first element, or returns false if full.
*/
private boolean linkFirst(Node node) {
// assert lock.isHeldByCurrentThread();
if (count >= capacity)
return false;
Node f = first;
node.next = f;
first = node;
if (last == null)
last = node;
else
f.prev = node;
++count;
notEmpty.signal();
return true;
}
/**
* Links node as last element, or returns false if full.
*/
private boolean linkLast(Node node) {
// assert lock.isHeldByCurrentThread();
if (count >= capacity)
return false;
Node l = last;
node.prev = l;
last = node;
if (first == null)
first = node;
else
l.next = node;
++count;
notEmpty.signal();
return true;
}
- 出队,,外部调用出队的逻辑和ArrayBlockingQueue一致
//头节点出队
private E unlinkFirst() {
// assert lock.isHeldByCurrentThread();
Node f = first;
if (f == null)
return null;
Node n = f.next;
E item = f.item;
f.item = null;
f.next = f; // help GC
first = n;
if (n == null)
last = null;
else
n.prev = null;
--count;
notFull.signal();
return item;
}
//尾节点出队
private E unlinkLast() {
// assert lock.isHeldByCurrentThread();
Node l = last;
if (l == null)
return null;
Node p = l.prev;
E item = l.item;
l.item = null;
l.prev = l; // help GC
last = p;
if (p == null)
first = null;
else
p.next = null;
--count;
notFull.signal();
return item;
}