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。