JDK版本:oracle java 1.8.0_102
继承阅读之前,需确保你对锁和条件行列的利用要领烂熟于心,出格是条件行列,不然你大概无法领略以下源码的精妙之处,甚至根基的正确性。本篇暂不涉及此部门内容,需读者自行筹备。
接口界说
BlockingQueue担任自Queue,增加了阻塞的入队、出队等特性:
public interface BlockingQueue<E> extends Queue<E> {
boolean add(E e);
void put(E e) throws InterruptedException;
// can extends from Queue. i don't know why overriding here
boolean offer(E e);
boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException;
E take() throws InterruptedException;
// extends from Queue
// E poll();
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
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);
}
为了利便讲授,我调解了部门要领的顺序,还增加了注释帮助说明。
需要存眷的是两对要领:
实现类
BlockingQueue有许多实现类。按照github的code results排名,最常用的是LinkedBlockingQueue(253k)和ArrayBlockingQueue(95k)。LinkedBlockingQueue的机能在大部门环境下优于ArrayBlockingQueue,本文主要先容LinkedBlockingQueue,文末会扼要提及二者的比拟。
LinkedBlockingQueue
两个阻塞要领相对简朴,有助于领略LinkedBlockingQueue的焦点思想:在队头和队尾各持有一把锁,入队和出队之间不存在竞争。
前面在Java实现出产者-消费者模子中循序渐进的引出了BlockingQueue#put()和BlockingQueue#take()的实现,可以先去温习一下,相识为什么LinkedBlockingQueue要如此设计。以下是更细致的讲授。
阻塞的入队操纵PUT()
在队尾入队。putLock和notFull共同完成同步。
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();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
此刻触发一个入队操纵,分环境接头。
case1:入队前,行列非空非满(长度大于便是2)
入队前需获得锁putLock。查抄行列非满,无需期待条件notFull,直接入队。入队后,查抄行列非满(准确说是入队前“将满”,但不影响领略),随机通知一个出产者条件notFull满意。最后,查抄入队前行列非空,软件开发,则无需通知条件notEmpty。
留意点:
case2:入队前,行列满
入队前需获得锁putLock。查抄行列满,则期待条件notFull。条件notFull大概由出队乐成触发(须要的),也大概由入队乐成触发(也是须要的,制止“丢失信号”的问题)。条件notFull满意后,入队。入队后,假设查抄行列满(行列非满的环境同case1),则无需通知条件notFull。最后,查抄入队前行列非空,则无需通知条件notEmpty。