文章目录
阻塞队列实现原理
插入和移除操作的处理方式
抛出异常 | 返回特殊值 | 一直阻塞 | 超时退出 | |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | / | / |
通过这两个Condition接口实现
private final Condition notEmpty; //take()
private final Condition notFull; //put()
当队列不可用时,都是调用的await()方法
如果队列不可用,就先保存当前线程的状态,然后进行通过unsafe包下的park()
进行阻塞
/**
* await()方法
*/
public final void await() throws InterruptedException {
//如果线程被中断
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
//如果队列不可用
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
/**
* park()方法
*/
public static void park(Object blocker) {
Thread t = Thread.currentThread();
//保存当前线程的状态
setBlocker(t, blocker);
//调用底层UNSAFE包下的park()方法,阻塞当前线程。
UNSAFE.park(false, 0L);
setBlocker(t, null);
}
/**
* UNSAFE.park()
*/
public native void park(boolean var1, long var2);
ArrayBlockingQueue(有界,长度为用户传入的)
存储格式(用数组的形式存储数据)
//元素数组
final Object[] items;
//获取元素的下标
int takeIndex;
//添加元素的下标
int putIndex;
//数组中元素的个数
int count;
初始化
/**
* 初始化阻塞队列
*/
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
//定义数组长度
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
//使用的是Condition
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
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();
}
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;
}
LinkedBlockingQueue(有界,默认为0x7fffffff)
存储格式(用一个Node节点记录数据)
static final class Node<E> {
//元素
E item;
//父节点
Node<E> prev;
//子节点
Node<E> next;
//构造方法
Node(E x) {
item = x;
}
}
//首节点
transient Node<E> first;
//尾节点
transient Node<E> last;
//节点的个数
private transient int count;
初始化
public LinkedBlockingDeque(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
//队列最大的长度
this.capacity = capacity;
}
put()方法
public void put(E e) throws InterruptedException {
putLast(e);
}
public void putLast(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
Node<E> node = new Node<E>(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
//当队列中的元素大于等于最大值时,调用await()方法
while (!linkLast(node))
notFull.await();
} finally {
lock.unlock();
}
}
take()方法
public E take() throws InterruptedException {
return takeFirst();
}
public E takeFirst() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
E x;
//当队列为空时,调用await()方法
while ( (x = unlinkFirst()) == null)
notEmpty.await();
return x;
} finally {
lock.unlock();
}
}
PriorityBlockingQueue(无界,put()方法可能会造成OOM问题)
存储格式
用==数组==的方式进行存储,只实现了一个Condition接口,notEmpty。
put()方法
public void put(E e) {
offer(e); // never need to block
}
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock();
int n, cap;
Object[] array;
while ((n = size) >= (cap = (array = queue).length))
//如果元素的长度大于了队列的长度,调用tryGrow(Object[] array, int oldCap)方法,使用新的数组。
tryGrow(array, cap);
try {
Comparator<? super E> cmp = comparator;
if (cmp == null)
siftUpComparable(n, e, array);
else
siftUpUsingComparator(n, e, array, cmp);
size = n + 1;
notEmpty.signal();
} finally {
lock.unlock();
}
return true;
}
/**
* tryGrow(Object[] array, int oldCap)方法,可能会造成OOM问题。
*/
private void tryGrow(Object[] array, int oldCap) {
lock.unlock(); // must release and then re-acquire main lock
Object[] newArray = null;
//如果当前标记的锁为0并且CAS成功
if (allocationSpinLock == 0 &&
UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,0, 1)) {
try {
//定义一个新的队列长度,新队列长度为:
// 如果老队列长度小于64:老队列长度+老队列长度+2
// 如果老队列长度大于等于64:老队列长度+老队列/2的长度
int newCap = oldCap + ((oldCap < 64) ?
(oldCap + 2) : // grow faster if small
(oldCap >> 1));
//如果新队列长度大于最大队列长度,可能会发生溢出
//MAX_ARRAY_SIZE = Integet.MAX_VALUE - 8;
if (newCap - MAX_ARRAY_SIZE > 0) { // possible overflow
int minCap = oldCap + 1;
if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
//抛出内存溢出错误
throw new OutOfMemoryError();
newCap = MAX_ARRAY_SIZE;
}
//新队列长度大于老队列长度并且队列没发生变化
if (newCap > oldCap && queue == array)
newArray = new Object[newCap];
} finally {
//将锁标记改为0
allocationSpinLock = 0;
}
}
if (newArray == null) // back off if another thread is allocating
Thread.yield();
lock.lock();
if (newArray != null && queue == array) {
queue = newArray;
System.arraycopy(array, 0, newArray, 0, oldCap);
}
}
SynchronousQueue(不存储元素的阻塞队列,每个put操作必须等待一个take操作,否则不能继续添加元素)
队列本身不存储任何元素
SynchronousQueue吞吐量高于LinkedBlocking和ArrayBlockingQueue
put()方法
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
if (transferer.transfer(e, false, 0) == null) {
Thread.interrupted();
throw new InterruptedException();
}
}
abstract E transfer(E e, boolean timed, long nanos);
take()方法
public E take() throws InterruptedException {
E e = transferer.transfer(null, false, 0);
if (e != null)
return e;
Thread.interrupted();
throw new InterruptedException();
}
abstract E transfer(E e, boolean timed, long nanos);
DelayQueue(支持优先级,可以延时获取元素的无界队列)
通过Priority实现,队列中的元素必须实现Delayed接口,只有在延时期满才能获取元素
通过一个Condition实现
private final Condition available = lock.newCondition();
LinkedTransferQueue(无界)
存储格式
链表
LinkedBlockingDeque(双向)
存储格式
链表
可以实现fork/join的工作窃取