这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战
本文主要讲BlockingQueue
BlockingQueue
public interface BlockingQueue<E> extends Queue<E> {
boolean add(E e);
boolean offer(E e);
void put(E e) throws InterruptedException;
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;
E take() throws InterruptedException;
E poll(long timeout, TimeUnit unit) throws InterruptedException;
//剩余容量, 无界队列的时候是Integer.Max
int remainingCapacity();
boolean remove(Object o);
public boolean contains(Object o);
//批量从队列中取出元素,无阻塞
int drainTo(Collection<? super E> c);
int drainTo(Collection<? super E> c, int maxElements);
}
复制代码
add,offer, put都是插入, add和offer无阻塞,但是在队列满时add会抛出异常,offer不会。put会阻塞,抛出中断异常。
remove非阻塞, poll和toke都会阻塞, 并抛出中断异常。
ArrayBlockingQueue
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();
}
复制代码
数组实现的环型队列,在构造函数中必须传入数组容量,分公平和非公平
/** The queued items */
final Object[] items;
//队头指针
int takeIndex;
//队尾指针
int putIndex;
//当前队列中元素个数
int count;
//锁和条件
final ReentrantLock lock;
private final Condition notEmpty;
private final Condition notFull;
复制代码
-
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; } 复制代码
-
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(); } 复制代码
LinkedBlockingQueue
基于单向链表的阻塞队列,队头和队尾是两个指针分开操作的, 使用了2把锁和2个条件。同时有一个AtomicInteger的原子变量记录count数。 构造函数中可以指定总容量, 默认Integer.MAX_VALUE
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
复制代码
private final int capacity;
//原子变量
private final AtomicInteger count = new AtomicInteger();
//单向链表头
transient Node<E> head;
//单向链表尾
private transient Node<E> last;
//两把锁 两个条件
private final ReentrantLock takeLock = new ReentrantLock();
private final Condition notEmpty = takeLock.newCondition();
private final ReentrantLock putLock = new ReentrantLock();
private final Condition notFull = putLock.newCondition();
复制代码
-
take
public E take() throws InterruptedException { E x; int c = -1; final AtomicInteger count = this.count; final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly(); try { while (count.get() == 0) { notEmpty.await(); } x = dequeue(); c = count.getAndDecrement(); if (c > 1) notEmpty.signal(); //如果还有元素通知其他take线程 } finally { takeLock.unlock(); } if (c == capacity) signalNotFull(); return x; } 复制代码
-
put
public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); int c = -1; Node<E> node = new Node<E>(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();//通知其他put线程 } finally { putLock.unlock(); } if (c == 0) signalNotEmpty(); } 复制代码
LinkedBlockingQueue和ArrayBlockingQueue的差异:
-
为了提供并发度, LinkedBlockingQueue分别控制队头队尾操作, put和put之间, take和take之间是互斥的,put和take之间不互斥, 但是count变量必须是原子的
-
因为各拿了一个锁, 当需要调用对方的signal时,必须加上对方的锁,比如signalNotEmpty
private void signalNotEmpty() { final ReentrantLock takeLock = this.takeLock; takeLock.lock(); try { notEmpty.signal(); } finally { takeLock.unlock(); } } 复制代码
PriorityBlockingQueue
按照元素优先级从小到大出队列,元素要可以比较大小实现Comparable接口
//数组实现二叉小根堆
private transient Object[] queue;
private transient int size;
private transient Comparator<? super E> comparator;
//锁和非空条件
private final ReentrantLock lock;
private final Condition notEmpty;
private transient volatile int allocationSpinLock;
private PriorityQueue<E> q;
public PriorityBlockingQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
public PriorityBlockingQueue(int initialCapacity) {
this(initialCapacity, null);
}
public PriorityBlockingQueue(int initialCapacity,
Comparator<? super E> comparator) {
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
this.comparator = comparator;
this.queue = new Object[initialCapacity];
}
复制代码
如果不指定大小,内部会设置11, 当超过11会自动扩容。
-
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(array, cap); //扩容 try { Comparator<? super E> cmp = comparator; if (cmp == null) siftUpComparable(n, e, array);//自带的comparable else siftUpUsingComparator(n, e, array, cmp); size = n + 1; notEmpty.signal(); } finally { lock.unlock(); } return true; } 复制代码
-
take
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); E result; try { while ( (result = dequeue()) == null) notEmpty.await(); } finally { lock.unlock(); } return result; } 复制代码
private E dequeue() { int n = size - 1; if (n < 0) return null; else { Object[] array = queue; E result = (E) array[0]; //永远是0 E x = (E) array[n]; array[n] = null; Comparator<? super E> cmp = comparator; //调整二叉堆 if (cmp == null) siftDownComparable(0, x, array, n); else siftDownUsingComparator(0, x, array, n, cmp); size = n; return result; } } 复制代码
和ArrayBlockingQueue机制类似, 主要区别在于使用数组实现了二叉堆,并且没有notFull条件, 能执行自动扩容
DelayQueue
延迟队列, 按照时间从小到大出队的PriorityQueue。放入DelayQueue的元素必须实现Delayed接口。
public interface Delayed extends Comparable<Delayed> {
long getDelay(TimeUnit unit);
}
复制代码
如果getDelay的返回值小于或等于0,说明元素到期。Delayed接口实现Comparable接口, 基于getDelay的返回值比较元素的大小。
//一把锁和一个非空条件
private final transient ReentrantLock lock = new ReentrantLock();
private final Condition available = lock.newCondition();
//优先级队列
private final PriorityQueue<E> q = new PriorityQueue<E>();
复制代码
-
take
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { for (;;) { E first = q.peek(); //取出堆顶元素 if (first == null) available.await(); else { long delay = first.getDelay(NANOSECONDS); if (delay <= 0) return q.poll(); first = null; // don't retain ref while waiting if (leader != null) //如果其他线程在等着,无限期等待。 available.await(); else { Thread thisThread = Thread.currentThread(); leader = thisThread; try { available.awaitNanos(delay); } finally { if (leader == thisThread) leader = null; } } } } } finally { if (leader == null && q.peek() != null) available.signal(); lock.unlock(); } } 复制代码
只有在队列为空的时候才阻塞,如果堆顶元素的延迟时间没到,也会阻塞。使用Thread leader记录等待堆顶元素的第一个线程。
-
put
public void put(E e) { offer(e); } public boolean offer(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { q.offer(e); if (q.peek() == e) { leader = null; available.signal(); } return true; } finally { lock.unlock(); } } 复制代码
SynchronousQueue
本身没有容量,先调用put,线程会阻塞, 知道另一个线程调用了take,两个线程同时解锁。反之亦然。
public SynchronousQueue() {
this(false);
}
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}
复制代码
公平先进先出,不公平先进后出
-
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(); } } 复制代码
-
take
public E take() throws InterruptedException { E e = transferer.transfer(null, false, 0); if (e != null) return e; Thread.interrupted(); throw new InterruptedException(); } 复制代码
核心是transfer接口。
abstract static class Transferer<E> {
abstract E transfer(E e, boolean timed, long nanos);
}
复制代码
根据e, 如果不是null,判定是消费者,否则是生产者。
如果是公平-队列模式
E transfer(E e, boolean timed, long nanos) {
QNode s = null; // constructed/reused as needed
boolean isData = (e != null);
for (;;) {
QNode t = tail;
QNode h = head;
if (t == null || h == null) // saw uninitialized value
continue; // spin
//队列为空或者当前线程和队列中元素是同一个模式
if (h == t || t.isData == isData) { // empty or same-mode
QNode tn = t.next;
if (t != tail) // inconsistent read
continue;
if (tn != null) { // lagging tail
advanceTail(t, tn);
continue;
}
if (timed && nanos <= 0) // can't wait
return null;
if (s == null)
s = new QNode(e, isData); //新建节点
if (!t.casNext(null, s)) // failed to link in
continue;
advanceTail(t, s); // swing tail and wait 后移tail进入阻塞状态
Object x = awaitFulfill(s, e, timed, nanos);
if (x == s) { // wait was cancelled
clean(t, s);
return null;
}
if (!s.isOffList()) { // not already unlinked 确定处于队列中的第一个元素
advanceHead(t, s); // unlink if head
if (x != null) // and forget fields
s.item = s;
s.waiter = null;
}
return (x != null) ? (E)x : e;
} else { // complementary-mode
QNode m = h.next; // node to fulfill
if (t != tail || m == null || h != head)
continue; // inconsistent read
Object x = m.item;
if (isData == (x != null) || // m already fulfilled
x == m || // m cancelled
!m.casItem(x, e)) { // lost CAS
advanceHead(h, m); // dequeue and retry
continue;
}
advanceHead(h, m); // successfully fulfilled
LockSupport.unpark(m.waiter);
return (x != null) ? (E)x : e;
}
}
}
复制代码
TransferQueue基于单向链表实现的队列,初始head和tail指向空节点
如果是非公平-栈模式
E transfer(E e, boolean timed, long nanos) {
SNode s = null; // constructed/reused as needed
int mode = (e == null) ? REQUEST : DATA;
for (;;) {
SNode h = head;
if (h == null || h.mode == mode) { // empty or same-mode
if (timed && nanos <= 0) { // can't wait
if (h != null && h.isCancelled())
casHead(h, h.next); // pop cancelled node
else
return null;
} else if (casHead(h, s = snode(s, e, h, mode))) {
SNode m = awaitFulfill(s, timed, nanos);
if (m == s) { // wait was cancelled
clean(s);
return null;
}
if ((h = head) != null && h.next == s)
casHead(h, s.next); // help s's fulfiller
return (E) ((mode == REQUEST) ? m.item : s.item);
}
} else if (!isFulfilling(h.mode)) { // try to fulfill 待匹配
if (h.isCancelled()) // already cancelled
casHead(h, h.next); // pop and retry
else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
for (;;) { // loop until matched or waiters disappear
SNode m = s.next; // m is s's match
if (m == null) { // all waiters are gone
casHead(s, null); // pop fulfill node
s = null; // use new node next time
break; // restart main loop
}
SNode mn = m.next;
if (m.tryMatch(s)) {
casHead(s, mn); // pop both s and m
return (E) ((mode == REQUEST) ? m.item : s.item);
} else // lost match
s.casNext(m, mn); // help unlink
}
}
} else { // help a fulfiller 待匹配
SNode m = h.next; // m is h's match
if (m == null) // waiter is gone
casHead(h, null); // pop fulfilling node
else {
SNode mn = m.next;
if (m.tryMatch(h)) // help match
casHead(h, mn); // pop both h and m
else // lost match
h.casNext(m, mn); // help unlink
}
}
}
}
复制代码