前言
文中的源码注释/结论是我个人学习过程中的理解/看法,多有漏误,后期的新看法/总结也不会再于本文中修正/添加,因此本文内容只可作为参考/提示使用,最新看法/总结以总结篇为准,链接在本文底部。
一 BlockingQueue(阻塞队列)接口源码及机制详解
接口
从本质上说,BlockingQueue(阻塞队列)接口(下文简称阻塞队列)应该属于Collection(集)框架的范畴,因为其继承了Queue(队列)接口。但由于其大多数情况都被用于容纳/管理执行器中任务,因此通常都被划分到Executor(执行器)框架的范畴中。为了契合Executor(执行器)框架的运行使用,阻塞队列在Queue(队列)接口的基础上增加了许多新特性/定义,该知识点的详细内容会在下文详述。
阻塞队列最大的特点是阻塞(这应该一眼就能看出来…),换句话说,其定义上是线程安全的,即其子类无论采用了何种实现方式,都必须保证线程安全。该定义意味着阻塞队列实现类的绝大多数方法实现都会是原子性的(否则无法保证线程安全),但对于批量方法就并非如此。例如addAll()、containsAll()及removeAll()等方法完全可以在底层循环调用add()、contains()及remove()方法来达到目的,因此在整体执行中可能伴随着并发。总的来说,即只要求单方法原子性执行,而批量方法除非特别指定,否则没有原子性执行的要求。因此,对于批量方法部分成功部分失败的情况是可以被接受的。例如在addAll()方法执行的过程中有元素抛出异常而导致后续元素添加失败,但前期元素添加成功的场景。
阻塞队列不允许存null值。接口规定一旦尝试在阻塞队列中存null值时必须抛出空异常,这是较为少见的,因为一般来说接口都不会对null值做强制的定义,而是交给子类自身去决定。阻塞队列之所以强制不允许存null值是因为null已经被用来作为标志位使用,具体原因与“方法的不同形式”有关,该知识点的详细内容会在下文详述。
阻塞队列可能存在容量限定,这种阻塞队列被称为有界队列(与之相对的是无界队列,即容量理论上只受限于堆内存大小。当然,在实际实现中其大多都受到int类型的物理限制)。有界队列的容量限定与常规的容量限定不同。在Collection(集)框架中,虽然也存在容量限定的说法,例如在创建ArrayList(数组列表)类对象时可以通过相应的构造方法来指定容量,但那实际上只是初始容量罢了,当存储的元素到达上限时无一例外都会触发扩容。但有界队列没有扩容的说法,是真正意义上的容量限定。一旦元素数量达到上限,则无法将向内保存元素,除非有元素因为被移除/拿取而空出了容量。
/**
* A {@link Queue} that additionally supports operations that wait for the queue to become non-empty when retrieving an element,
* and wait for space to become available in the queue when storing an element.
* 一个支持更多的操作的队列,例如当检索一个元素时等待成为非空队列,以及当保存一个元素时等待队列中的空间成为可用的(即空闲的)。
* <p>
* {@code BlockingQueue} methods come in four forms, with different ways of handling operations that cannot be satisfied immediately,
* but may be satisfied at some point in the future: one throws an exception, the second returns a special value (either {@code null}
* or {@code false}, depending on the operation), the third blocks the current thread indefinitely until the operation can succeed,
* and the fourth blocks for only a given maximum time limit before giving up. These methods are summarized in the following table:
* BlockingQueue方法有四种形式,有不同的处理操作的方式,这些操作不能立即得到满足,但可能在将来的一些时候得到满足(即
* 一个相同的功能可能有四种不同的方法(名字可能不一样),这是为了满足不同的使用方式):一是抛出异常;二是返回一个特殊
* 值(要么null,要么false,(具体)依赖操作(本身的实现));三是无限地阻塞当前线程直至操作可以成功;四是放弃之前阻塞
* 指定最大限度限制时间。这些方法总结在下方表中:
* <p>
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <caption>Summary of BlockingQueue methods</caption>
* <caption>BlockingQueue方法总结</caption>
* <tr>
* <td></td>
* <td ALIGN=CENTER><em>Throws exception</em></td>
* <td ALIGN=CENTER><em>抛出异常</em></td>
* <td ALIGN=CENTER><em>Special value</em></td>
* <td ALIGN=CENTER><em>特殊值</em></td>
* <td ALIGN=CENTER><em>Blocks</em></td>
* <td ALIGN=CENTER><em>阻塞(无限阻塞)</em></td>
* <td ALIGN=CENTER><em>Times out</em></td>
* <td ALIGN=CENTER><em>超时(有限阻塞)</em></td>
* </tr>
* <tr>
* <td><b>Insert</b></td>
* <td><b>新增</b></td>
* <td>{@link #add add(e)}</td>
* <td>{@link #offer offer(e)}</td>
* <td>{@link #put put(e)}</td>
* <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
* </tr>
* <tr>
* <td><b>Remove</b></td>
* <td><b>移除</b></td>
* <td>{@link #remove remove()}</td>
* <td>{@link #poll poll()}</td>
* <td>{@link #take take()}</td>
* <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
* </tr>
* <tr>
* <td><b>Examine</b></td>
* <td><b>检查</b></td>
* <td>{@link #element element()}</td>
* <td>{@link #peek peek()}</td>
* <td><em>not applicable</em></td>
* <td><em>not applicable</em></td>
* </tr>
* </table>
*
* <p>
* A {@code BlockingQueue} does not accept {@code null} elements. Implementations throw {@code NullPointerException} on attempts
* to {@code add}, {@code put} or {@code offer} a {@code null}. A {@code null} is used as a sentinel value to indicate failure of {@code poll}
* operations.
* BlockingQueue无法接受null元素(即不能存null值)。实现在试图add()、put()或offer()(即新增)一个null时抛出空异常 。null已经被使用
* 作为标记值来表示poll()方法操作失败。
* <p>
* A {@code BlockingQueue} may be capacity bounded. At any given time it may have a {@code remainingCapacity} beyond which no
* additional elements can be {@code put} without blocking. A {@code BlockingQueue} without any intrinsic capacity constraints always
* reports a remaining capacity of {@code Integer.MAX_VALUE}.
* BlockingQueue可能容积有限(即容量上限)。在任意指定时间,它都可能具有剩余容积,超出该容量(应该说是剩余容量归0,可能
* 是我英文不好,翻译有点问题),则没有新增的元素能够放置(队列中),除非是阻塞(的情况下放置,即一直等待到有剩余容量为止)。
* <p>
* {@code BlockingQueue} implementations are designed to be used primarily for producer-consumer queues, but additionally support
* the {@link Collection} interface. So, for example, it is possible to remove an arbitrary element from a queue using {@code remove(x)}.
* However, such operations are in general <em>not</em> performed very efficiently, and are intended for only occasional use, such as
* when a queued message is cancelled.
* BlockingQueue实现主要使用生产者 - 消费者队列(即观察者模式)设计,但额外支持Collection接口(即实现了Collection接口)。所
* 以,使用remove()方法从队列中移除一个任意元素是可能的。无论如何,这些操作通常执行的不是非常高效,并且只为偶尔使用预留,
* 例如当一个队列消息被取消(即对于Collection接口方法虽然有所实现,但是只是为了一些极其特殊的使用场景准备,一般来说是不会去
* 使用的)。
* <p>
* {@code BlockingQueue} implementations are thread-safe. All queuing methods achieve their effects atomically using internal locks or
* other forms of concurrency control. However, the <em>bulk</em> Collection operations {@code addAll}, {@code containsAll},
* {@code retainAll} and {@code removeAll} are <em>not</em> necessarily performed atomically unless specified otherwise in an implementation.
* So it is possible, for example, for {@code addAll(c)} to fail (throwing an exception) after adding only some of the elements in {@code c}.
* BlockingQueue实现是线程安全的。所有队列方法使用内部锁或其它并发控制形式原子的实现它们的效果。但是,大批的(批量的)
* 操作集合addAll()、containsAll()和removeAll()没有必要原子性地执行,除非在实现中特殊指定。所以addAll()方法新增了集合中的
* 一些元素后失败(抛出一个异常)是可能的(添加了部分元素后达到了队列的容量上限上限导致)。
* <p>
* A {@code BlockingQueue} does <em>not</em> intrinsically support any kind of "close" or "shutdown" operation
* to indicate that no more items will be added. The needs and usage of such features tend to be implementation-dependent. For example,
* a common tactic is for producers to insert special <em>end-of-stream</em> or <em>poison</em> objects, that are interpreted accordingly
* when taken by consumers.
* BlockingQueue本质上不支持任意close或shutdown类型(操作);操作表示没有更多的条目将新增。如此特性的需要和使用倾向于独立的
* 实现。例如一种常见的策略是生产者插入特殊的流末尾或有毒对象,当消费者使用这些对象时,会相应地进行解释。
* <p>
* Usage example, based on a typical producer-consumer scenario. Note that a {@code BlockingQueue} can safely be used with multiple
* producers and multiple consumers.
* 使用实例,以主要的生产者-消费者场景为基础。注意BlockingQueue可以在多生产者和多消费者的情况下安全的使用。
* <pre> {@code
* class Producer implements Runnable {
*
* private final BlockingQueue queue;
*
* Producer(BlockingQueue q) {
* queue = q;
* }
*
* public void run() {
* // 连续不断的向队列中存放产品。
* try {
* while (true) { queue.put(produce()); }
* } catch (InterruptedException ex) { ... handle ...}
* }
*
* Object produce() { ... }
* }
*
* class Consumer implements Runnable {
*
* private final BlockingQueue queue;
*
* Consumer(BlockingQueue q) {
* queue = q;
* }
*
* public void run() {
* // 连续不断的从队列中取出产品并消费。
* try {
* while (true) { consume(queue.take()); }
* } catch (InterruptedException ex) { ... handle ...}
* }
* void consume(Object x) { ... }
* }
*
* class Setup {
* void main() {
* // 在多线程的环境下进行生产及消费。
* BlockingQueue q = new SomeQueueImplementation();
* Producer p = new Producer(q);
* Consumer c1 = new Consumer(q);
* Consumer c2 = new Consumer(q);
* new Thread(p).start();
* new Thread(c1).start();
* new Thread(c2).start();
* }
* }}</pre>
*
* <p>
* Memory consistency effects: As with other concurrent collections, actions in a thread prior to placing an object into a {@code BlockingQueue}
* <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a> actions subsequent to the access or removal of that element
* from the {@code BlockingQueue} in another thread.
* 内存一致性影响:和其它并发集合(即线程安全的线程)一样,将对象放入BlockingQueue之前的线程操作发生在访问(同一个线程)或从另一个
* 线程删除BlockingQueue中该元素之后的操作之前(通俗的说,就是元素存入之前的操作发生于元素存入之后的操作之前,无论是否在一个线程)。
* <p>
* This interface is a member of the <a href="{@docRoot}/../technotes/guides/collections/index.html"> Java Collections Framework</a>.
* 这个接口是Java 集合框架的成员。
*
* @param <E> the type of elements held in this collection 在集合中的元素持有的类型
* @author Doug Lea
* @Description: 阻塞队列接口
* @since 1.5
*/
public interface BlockingQueue<E> extends Queue<E> {
...
}
方法
boolean add(E e) —— 新增 —— 继承自Collection(集)接口,用于插入一个元素。该方法是插入操作“异常”形式的定义。当队列容量已满而无法容纳插入的元素时会直接抛出IllegalStateException。
/**
* Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions, returning {@code true}
* upon success and throwing an {@code IllegalStateException} if no space is currently available. When using a capacity-restricted queue, it is generally
* preferable to use {@link #offer(Object) offer}.
* 新增指定元素至队列,如果是立即执行没有违反容量限制的情况,则插入成功后返回true;如果当前没有可用空间则抛出一个IllegalStateException(
* 即如果有容量则正常的新增;没有容量就抛出异常...因此该方法不会返回false,因为在失败时会直接抛出异常)。当使用一个容量有限制的队列,
* 通常使用offer()方法更好。
*
* @param e the element to add 新增的元素
* @return {@code true} (as specified by {@link Collection#add}) 返回值true
* @throws IllegalStateException if the element cannot be added at this time due to capacity restrictions 如果元素由于容量限制无法新增
* @throws ClassCastException if the class of the specified element prevents it from being added to this queue 如果指定元素的类妨碍其新增至该队列
* @throws NullPointerException if the specified element is null 如果指定元素为null
* @throws IllegalArgumentException if some property of the specified element prevents it from being added to this queue
* 如果指定元素的特性妨碍其新增至该队列
*/
@Override
boolean add(E e);
boolean offer(E e) —— 提供 —— 继承自Queue(队列)接口,用于插入一个元素。该方法是插入操作“特殊值”形式的定义。当队列容量已满而无法容纳插入的元素时会返回false。当使用限定了容量的队列时更适合使用此方法,因为不会因为频繁的触及容量上限而不断抛出异常。
/**
* Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions, returning {@code true} upon
* success and {@code false} if no space is currently available. When using a capacity-restricted queue, this method is generally preferable to {@link #add},
* which can fail to insert an element only by throwing an exception.
* 新增指定元素至队列,如果是立即执行没有违反容量限制的情况则成功之后返回true,如果没有空间当前可用则返回false。当使用容量有限的队列时,
* 这个方法通常比add()方法更好,其新增一个元素失败时抛出一个异常。
*
* @param e the element to add 新增的元素
* @return {@code true} if the element was added to this queue, else {@code false} 如果元素新增至队列返回true,否则false
* @throws ClassCastException if the class of the specified element prevents it from being added to this queue 如果指定元素的类妨碍其新增至该队列
* @throws NullPointerException if the specified element is null 如果指定元素为null
* @throws IllegalArgumentException if some property of the specified element prevents it from being added to this queue
* 如果指定元素的特性妨碍其新增至该队列
*/
@Override
boolean offer(E e);
void put(E e) —— 放置 —— 接口自定义,用于插入一个元素。该方法是插入操作“阻塞”形式的定义。当队列容量已满而无法容纳插入的元素时阻塞,直至队列空出容量后执行。
/**
* Inserts the specified element into this queue, waiting if necessary for space to become available.
* 新增指定的元素至队列,如果必要(即当前没有可用容量)则等待到空间成为可用的。
*
* @param e the element to add 新增的元素
* @throws InterruptedException if interrupted while waiting 如果在等待时中断
* @throws ClassCastException if the class of the specified element prevents it from being added to this queue
* 如果指定元素的类妨碍其新增至该队列
* @throws NullPointerException if the specified element is null 如果指定元素为null
* @throws IllegalArgumentException if some property of the specified element prevents it from being added to this queue
* 如果指定元素的特性妨碍其新增至该队列
*/
void put(E e) throws InterruptedException;
boolean offer(E e, long timeout, TimeUnit unit) —— 提供 —— 接口自定义,用于插入一个元素。该方法是插入操作“超时”形式的定义。当队列容量已满而无法容纳插入的元素时阻塞,直至队列空出容量后执行或因为超时而返回false(或抛出超时异常,这个与具体的子类实现有关)。
/**
* Inserts the specified element into this queue, waiting up to the specified wait time if necessary for space to become available.
* 新增指定元素至队列,如果必要(即没有可用的容量)则等待至指定的等到时间直至空间变为可用。
*
* @param e the element to add 新增的元素
* @param timeout how long to wait before giving up, in units of {@code unit} 放弃前要等待多久
* @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter 时间单位
* @return {@code true} if successful, or {@code false} if the specified waiting time elapses before space is available
* 如果成功则返回true,空间可用之前指定的等待时间过去(消逝)则返回false
* @throws InterruptedException if interrupted while waiting 如果在等待时中断
* @throws ClassCastException if the class of the specified element prevents it from being added to this queue
* 如果指定元素的类妨碍其新增至该队列
* @throws NullPointerException if the specified element is null 如果指定元素为null
* @throws IllegalArgumentException if some property of the specified element prevents it from being added to this queue
* 如果指定元素的特性妨碍其新增至该队列
*/
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;
E take() —— 拿取 —— 接口自定义,用于移除一个元素。该方法是移除操作“阻塞”形式的定义。当队列容量为空而无法移除元素时阻塞,直至有新元素入队后执行。
/**
* Retrieves and removes the head of this queue, waiting if necessary until an element becomes available.
* 检索并移除队列头(元素),如果必要(即队列中没有元素)则等待直至元素变可用(即有元素入队)。
*
* @return the head of this queue 队列头(元素)
* @throws InterruptedException if interrupted while waiting 如果在等待中中断
*/
E take() throws InterruptedException;
E poll(long timeout, TimeUnit unit) —— 轮询 —— 接口自定义,用于移除一个元素。该方法是移除操作“超时”形式的定义。当队列容量为空而无法移除元素时阻塞,直至有新元素入队后执行或因为超时而返回false(或抛出超时异常,这个与具体的子类实现有关)。
/**
* Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an element to become available.
* 检索并移除队列头(元素),如果必要(即队列中没有元素)则等待指定的等待时间直至元素变可用(即有元素入队)。
*
* @param timeout how long to wait before giving up, in units of {@code unit} 等待时间
* @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter 等待时间单位
* @return the head of this queue, or {@code null} if the specified waiting time elapses before an element is available
* 队列头(元素),如果在元素变可用之前指定的等待时间过去则返回null
* @throws InterruptedException if interrupted while waiting 如果在等待中中断
*/
E poll(long timeout, TimeUnit unit) throws InterruptedException;
int remainingCapacity() —— 剩余容量 —— 接口自定义,用于获取队列可用的容量。该方法由于并发的原因,并不推荐将该方法的返回值作为是否插入的判断依据(至少不能作为精确的判断依据),因为在获取后及当前线程插入前有其它线程执行了插入操作导致容量耗尽。
/**
* Returns the number of additional elements that this queue can ideally (in the absence of memory or resource constraints) accept without blocking,
* or {@code Integer.MAX_VALUE} if there is no intrinsic limit.
* 返回可添加的元素数量。即队列理想中能够接受而不阻塞(的元素数量)或int类型的最大值如果没有一个固定的限制(即返回剩下可容纳的元素数量,
* 如果是一个无限队列,则直接返回int类型的最大值)
* <p>
* Note that you <em>cannot</em> always tell if an attempt to insert an element will succeed by inspecting {@code remainingCapacity} because it may
* be the case that another thread is about to insert or remove an element.
* 注意你不能经常通过检查remainingCapacity试图成功新增一个元素,因为它可能是这样的情况:另一个线程即将新增或移除一个元素(这种情况下
* remainingCapacity就是一个已过期的数据,因此如果真的要这么写就需要进行额外的同步,这是多线程中常见的竞态条件情况)。
*
* @return the remaining capacity 剩余容量
*/
int remainingCapacity();
boolean remove(Object o) —— 移除(false:失败,true:成功) —— 继承自Collection(集)接口,用于移除一个指定的元素。BlockingQueue(阻塞队列)接口的实现主要使用FIFO设计,但也额外支持Collection(集)接口。所以使用remove()方法从队列的任意位置移除一个任意元素是可能的。但一般来说性能并不高效,并且只为偶尔使用预留,因此不推荐调用该方法。
/**
* Removes a single instance of the specified element from this queue, if it is present. More formally, removes an element {@code e} such that
* {@code o.equals(e)}, if this queue contains one or more such elements. Returns {@code true} if this queue contained the specified element (or equivalently,
* if this queue changed as a result of the call).
* 从队列中移除指定元素的单个实例(如果元素是存在的)。更正式的,如果队列包含一个或多个该元素,移除一个元素e应该通过equals()方法判断。如果
* 该队列包含指定的元素,则返回true(或者,如果该队列因调用而发生更改,则返回同样的结果(这句话看不懂...应该是说即使元素不存在,但如果因为该
* 移除操作使得队列发生了变化,也一样要返回true,因为正常情况下不应该会发生变化))。
*
* @param o element to be removed from this queue, if present 移除的元素
* @return {@code true} if this queue changed as a result of the call 如果队列应该调用而发生了变化。
* @throws ClassCastException if the class of the specified element is incompatible with this queue (<a href="../Collection.html#optional-restrictions">optional</a>)
* 如果指定元素的类与队列不兼容
* @throws NullPointerException if the specified element is null (<a href="../Collection.html#optional-restrictions">optional</a>)
* 如果指定元素为null
*/
@Override
boolean remove(Object o);
public boolean contains(Object o) —— 包含(false:不包含,true:包含) —— 继承自Collection(集)接口,用于判断是否包含指定元素。
/**
* Returns {@code true} if this queue contains the specified element. More formally, returns {@code true} if and only if this queue contains at least one
* element {@code e} such that {@code o.equals(e)}.
* 如果队列包含指定元素则返回true。更正式的,通过通过equals()方法判断至少包含一个元素返回true。
*
* @param o object to be checked for containment in this queue 在队列中检查是否包含
* @return {@code true} if this queue contains the specified element 如果队列中包含指定元素
* @throws ClassCastException if the class of the specified element is incompatible with this queue (<a href="../Collection.html#optional-restrictions">optional</a>)
* 如果指定元素的类与队列不兼容
* @throws NullPointerException if the specified element is null (<a href="../Collection.html#optional-restrictions">optional</a>)
* 如果指定元素为null
*/
@Override
public boolean contains(Object o);
int drainTo(Collection<? super E> c) —— 流失 —— 接口自定义,用于将队列中的所有元素迁移至指定的集中。该方法不允许将队列自身作为参数传入,否则会抛出IllegalArgumentException。如果在迁移过程中抛出了异常,则可能出现元素丢失的情况,即元素已经从队列中移除,但未加入到指定的集中(至于异常后是否中断迁移,就看各自的实现了)。如果在元素迁移的过程中对指定的集进行了修改,则drainTo()方法的执行结果就不确定了…意思就是不强制对这种场景进行定义,你可以自行实现在这种场景下你想要的效果。
/**
* Removes all available elements from this queue and adds them to the given collection. This operation may be more efficient than repeatedly polling
* this queue. A failure encountered while attempting to add elements to collection {@code c} may result in elements being in neither, either or both
* collections when the associated exception is thrown. Attempts to drain a queue to itself result in {@code IllegalArgumentException}. Further, the
* behavior of this operation is undefined if the specified collection is modified while the operation is in progress.
* 从队列中移除所有可用元素并新增它们至指定的集合。这个操作可能比屡次轮询这个队列更加高效。在试图新增元素至集合期间遭遇失败可能导致
* 关联元素在抛出异常时不在任意一个集合中(已经从队列中移除,但还没有加入指定的集合中)。试图清除队列到自身会导致 IllegalArgumentException
* (即传入的指定集合是队列本身)。此外,如果在操作进行时修改了指定的集合,则此操作的行为未定义(即drainTo()方法在执行的过程中指定集合
* 被修改了,则drainTo()方法的执行结果就不确定了)。
*
* @param c the collection to transfer elements into 迁移的集合
* @return the number of elements transferred 被迁移的元素数量
* @throws UnsupportedOperationException if addition of elements is not supported by the specified collection 如果元素的增加不支持指定的集合
* @throws ClassCastException if the class of an element of this queue prevents it from being added to the specified collection
* 如果队列的元素类型妨碍其新增至指定的集合
* @throws NullPointerException if the specified collection is null 如果指定集合为null
* @throws IllegalArgumentException if the specified collection is this queue, or some property of an element of this queue prevents it from being
* added to the specified collection
* 如果指定指定集合是当前队列,或者元素的某些特性妨碍其添加至指定的集合
*/
int drainTo(Collection<? super E> c);
int drainTo(Collection<? super E> c, int maxElements) —— 流失 —— 接口自定义,用于将队列中的最多指定数量的元素迁移至指定的集中。该方法不允许将队列自身作为参数传入,否则会抛出IllegalArgumentException。如果在迁移过程中抛出了异常,则可能出现元素丢失的情况,即元素已经从队列中移除,但未加入到指定的集中(至于异常后是否中断迁移,就看各自的实现了)。如果在元素迁移的过程中对指定的集进行了修改,则drainTo()方法的执行结果就不确定了…意思就是不强制对这种场景进行定义,你可以自行实现在这种场景下你想要的效果。如果队列中元素不足指定的数量则迁移所有的元素。
/**
* Removes at most the given number of available elements from this queue and adds them to the given collection. A failure encountered while attempting
* to add elements to collection {@code c} may result in elements being in neither, either or both collections when the associated exception is thrown.
* Attempts to drain a queue to itself result in {@code IllegalArgumentException}. Further, the behavior of this operation is undefined if the specified
* collection is modified while the operation is in progress.
* 移除最多指定数量的可用元素并将他们添加至指定的集合。在试图新增元素至集合期间遭遇失败可能导致关联元素在抛出异常时不在任意一个集合中
* (已经从队列中移除,但还没有加入指定的集合中)。此外,如果在操作进行时修改了指定的集合,则此操作的行为未定义(即drainTo()方法在执行
* 的过程中指定集合被修改了,则drainTo()方法的执行结果就不确定了)。
*
* @param c the collection to transfer elements into 迁移的集合
* @param maxElements the maximum number of elements to transfer 迁移元素的做大数量
* @return the number of elements transferred 迁移元素的数量
* @throws UnsupportedOperationException if addition of elements is not supported by the specified collection 如果元素的增加不支持指定的集合
* @throws ClassCastException if the class of an element of this queue prevents it from being added to the specified collection
* 如果队列的元素类型妨碍其新增至指定的集合
* @throws NullPointerException if the specified collection is null 如果指定集合为null
* @throws IllegalArgumentException if the specified collection is this queue, or some property of an element of this queue prevents it from being
* added to the specified collection
* 如果指定指定集合是当前队列,或者元素的某些特性妨碍其添加至指定的集合
*/
int drainTo(Collection<? super E> c, int maxElements);