remove()
或 poll()
所移除的元素。在 FIFO 队列中,全部的新元素都插入队列的末尾。其余种类的队列可能使用不一样的元素放置规则。每一个 Queue 实现必须指定其顺序属性。Collection
操做外,队列还提供其余的插入、提取和检查操做。每一个方法都存在两种形式:一种抛出异常(操做失败时),另外一种返回一个特殊值(null 或 false,具体取决于操做)。BlockingQueue
接口定义了那些等待元素出现或等待队列中有可用空间的方法,这些方法扩展了此接口。 抛出异常 返回特殊值
插入:add(e) offer(e) 插入一个元素
移除:remove() poll() 移除和返回队列的头
检查:element() peek() 返回但不移除队列的头。html
此接口是 Java Collections Framework 的成员。java
Java Queue接口扩展了Collection接口。Collection接口 externs Iterable接口。算法
子接口:BlockingQueue, Deque, BlobkingDequeue编程
一些最经常使用的Queue实现类是LinkedList,ArrayBlickingQueue, LinkedBlockingQueue,PriorityQueue, PriorityBlockingQueue。api
boolean add(E e) //将指定的元素插入此队列(若是当即可行且不会违反容量限制),在成功时返回 true,若是当前没有可用的空间,则抛出 IllegalStateException。 E element() //获取,可是不移除此队列的头。 boolean offer(E e) //将指定的元素插入此队列(若是当即可行且不会违反容量限制),当使用有容量限制的队列时,此方法一般要优于 add(E),后者可能没法插入元素,而只是抛出一个异常。 E peek() //获取但不移除此队列的头;若是此队列为空,则返回 null。 E poll() //获取并移除此队列的头,若是此队列为空,则返回 null。 E remove() //获取并移除此队列的头。
一个基于连接节点的无界线程安全队列。数组
一个基于连接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部是队列中时间最短的元素。新的元素插入到队列的尾部,队列获取操做从队列头部得到元素。当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。缓存
此队列不容许使用 null 元素。安全
此实现采用了有效的“无等待 (wait-free)”算法,该算法基于 Maged M. Michael 和 Michael L. Scott 合著的 Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms 中描述的算法。数据结构
须要当心的是,与大多数 collection 不一样,size 方法不是 一个固定时间操做。因为这些队列的异步特性,肯定当前元素的数量须要遍历这些元素。多线程
ConcurrentLinkedQueue
以前的线程中的操做 happen-before 随后经过另外一线程从 ConcurrentLinkedQueue
访问或移除该元素的操做。线程安全的,volatile + CAS 可知入队出队函数都是操做volatile变量:head,tail。因此要保证队列线程安全只须要保证对这两个Node操做的可见性和原子性,因为volatile自己保证可见性,因此只须要看下多线程下若是保证对着两个变量操做的原子性。对于offer操做是在tail后面添加元素,也就是调用tail.casNext方法,而这个方法是使用的CAS操做,只有一个线程会成功,而后失败的线程会循环一下,从新获取tail,而后执行casNext方法。对于poll也是这样的。
一个线性 collection,支持在两端插入和移除元素。名称 deque 是“double ended queue(双端队列)”的缩写,一般读为“deck”。大多数 Deque 实现对于它们可以包含的元素数没有固定限制,但此接口既支持有容量限制的双端队列,也支持没有固定大小限制的双端队列。
队列:此接口扩展了 Queue
接口。在将双端队列用做队列时,将获得 FIFO(先进先出)行为。将元素添加到双端队列的末尾,从双端队列的开头移除元素。
堆栈:双端队列也可用做 LIFO(后进先出)堆栈。应优先使用此接口而不是遗留 Stack
类。在将双端队列用做堆栈时,元素被推入双端队列的开头并从双端队列开头弹出。堆栈方法彻底等效于 Deque 方法,
LinkedList是基于链表实现的,从源码能够看出是一个双向链表。除了当作链表使用外,它也能够被看成堆栈、队列或双端队列进行操做。
LinkedList不是线程安全的,继承AbstractSequentialList实现List、Deque、Cloneable、Serializable。
并发队列ConcurrentLinkedDeque,这是一个非阻塞,无锁,无界 ,线程安全双端操做的队列。简单说就是ConcurrentLinkedQueue的升级版,在JDK7以后才提供。该队列也不容许空元素,并且size方法并非常量时间,其须要遍历链表,此时并发修改链表会形成统计size不正确。一样,bulk操做和equal以及toArray方法不保证原子性。
JDK7提供了7个阻塞队列。分别是
Integer.MAX_VALUE
。 2 31-1 Integer.MAX_VALUE
。 2 31-1 Queue
,这两个操做是:获取元素时等待队列变为非空,以及存储元素时等待空间变得可用(阻塞)。BlockingQueue 不接受 null 元素。试图 add、put 或 offer 一个 null 元素时,某些实现会抛出 NullPointerException。null 被用做指示 poll 操做失败的警惕值。
BlockingQueue 能够是限定容量的。它在任意给定时间均可以有一个 remainingCapacity,超出此容量,便没法无阻塞地 put 附加元素。没有任何内部容量约束的 BlockingQueue 老是报告 Integer.MAX_VALUE 的剩余容量。
BlockingQueue 实现主要用于生产者-使用者队列,BlockingQueue 能够安全地与多个生产者和多个使用者一块儿使用。但它另外还支持 Collection
接口。所以,举例来讲,使用 remove(x) 从队列中移除任意一个元素是有可能的。然而,这种操做一般不 会有效执行,只能有计划地偶尔使用,好比在取消排队信息时。
BlockingQueue 实现是线程安全的。全部排队方法均可以使用内部锁或其余形式的并发控制来自动达到它们的目的。然而,大量的 Collection 操做(addAll、containsAll、retainAll 和 removeAll)没有 必要自动执行,除非在实现中特别说明。所以,举例来讲,在只添加了 c 中的一些元素后,addAll(c) 有可能失败(抛出一个异常)。
BlockingQueue 实质上不 支持使用任何一种“close”或“shutdown”操做来指示再也不添加任何项。这种功能的需求和使用有依赖于实现的倾向。例如,一种经常使用的策略是:对于生产者,插入特殊的 end-of-stream 或 poison 对象,并根据使用者获取这些对象的时间来对它们进行解释。
内存一致性效果:当存在其余并发 collection 时,将对象放入 BlockingQueue
以前的线程中的操做 happen-before 随后经过另外一线程从 BlockingQueue
中访问或移除该元素的操做。
一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部 是在队列中存在时间最长的元素。队列的尾部 是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列获取操做则是从队列头部开始得到元素。
这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦建立了这样的缓存区,就不能再增长其容量。试图向已满队列中放入元素会致使操做受阻塞;试图从空队列中提取元素将致使相似阻塞。
此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。默认状况下,不保证是这种排序。然而,经过将公平性 (fairness) 设置为 true 而构造的队列容许按照 FIFO 顺序访问线程。公平性一般会下降吞吐量,但也减小了可变性和避免了“不平衡性”。
ArrayBlockingQueue内部有个循环数组items用来存放队列元素,putIndex下标标示入队元素下标,takeIndex是出队下标,count统计队列元素个数,从定义可知道并无使用volatile修饰,这是由于访问这些变量使用都是在锁块内,并不存在可见性问题。
有个独占锁lock用来对出入队操做加锁,这致使同时只有一个线程能够访问入队出队,
notEmpty,notFull条件变量用来进行出入队的同步。另外构造函数必须传入队列大小参数,因此为有界队列,默认是Lock为非公平锁。
offer操做:在队尾插入元素,若是队列满则返回false,否者入队返回true。因为在操做共享变量前加了锁【final ReentrantLock lock = this.lock; 获取独占锁 lock.lock();】,因此不存在内存不可见问题,加过锁后获取的共享变量都是从主内存获取的,而不是在CPU缓存或者寄存器里面的值,释放锁后修改的共享变量值会刷新会主内存中。另外这个队列是使用循环数组实现,因此计算下一个元素存放下标时候有些特殊。【i=putIndex; return(++i == items.length) ? 0 : i;】另外insert后调用 notEmpty.signal();是为了激活调用notEmpty.await()阻塞后放入notEmpty条件队列中的线程。
一个由连接节点支持的可选有界队列。
一个基于已连接节点的、范围任意的 blocking queue。此队列按 FIFO(先进先出)排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部 是在队列中时间最短的元素。新元素插入到队列的尾部,而且队列获取操做会得到位于队列头部的元素。连接队列的吞吐量一般要高于基于数组的队列,可是在大多数并发应用程序中,其可预知的性能要低。
可选的容量范围构造方法参数做为防止队列过分扩展的一种方法。若是未指定容量,则它等于 Integer.MAX_VALUE
。除非插入节点会使队列超出容量,不然每次插入后会动态地建立连接节点。
一个基于优先级堆的无界优先级阻塞队列。
PriorityQueue
相同的顺序规则,而且提供了阻塞获取操做。虽然此队列逻辑上是无界的,可是资源被耗尽时试图执行 add 操做也将失败(致使 OutOfMemoryError)。 Collection
和 Iterator
接口的全部可选 方法。iterator()
方法中提供的迭代器并不 保证以特定的顺序遍历 PriorityBlockingQueue 的元素。若是须要有序地进行遍历,则应考虑使用 Arrays.sort(pq.toArray())。此外,可使用方法 drainTo 按优先级顺序移除 所有或部分元素,并将它们放在另外一个 collection 中。
一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素。
DelayQueue队列中每一个元素都有个过时时间,而且队列是个优先级队列,当从队列获取元素时候,只有过时元素才会出队列。
Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部 是延迟期满后保存时间最长的 Delayed 元素。若是延迟都尚未期满,则队列没有头部,而且 poll 将返回 null。
当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于等于 0 的值时,将发生到期。即便没法使用 take 或 poll 移除未到期的元素,也不会将这些元素做为正常元素对待。例如,size 方法同时返回到期和未到期元素的计数。
此队列不容许使用 null 元素。
一个不存储元素、没有内部容量的阻塞同步队列。
SynchronousQueue的吞吐量高于LinkedBlockingQueue 和 ArrayBlockingQueue。
一个不存储元素、没有内部容量的阻塞队列,其中每一个插入操做必须等待另外一个线程的对应移除操做 ,反之亦然。同步队列没有任何内部容量,甚至连一个队列的容量都没有。不能在同步队列上进行 peek,由于仅在试图要移除元素时,该元素才存在;除非另外一个线程试图移除某个元素,不然也不能(使用任何方法)插入元素;也不能迭代队列,由于其中没有元素可用于迭代。队列的头 是尝试添加到队列中的首个已排队插入线程的元素;若是没有这样的已排队线程,则没有可用于移除的元素而且 poll() 将会返回 null。对于其余 Collection 方法(例如 contains),SynchronousQueue 做为一个空 collection。
此队列不容许 null 元素。
同步队列相似于 CSP 和 Ada 中使用的 简单汇集(rendezvous)机制信道。它很是适合于传递性设计,在这种设计中,在一个线程中运行的对象要将某些信息、事件或任务传递给在另外一个线程中运行的对象,它就必须与该对象同步。
对于正在等待的生产者和使用者线程而言,此类支持可选的公平排序策略。默认状况下不保证这种排序。可是,使用公平设置为 true 所构造的队列可保证线程以 FIFO 的顺序进行访问。
LinkedTransferQueue是一个由链表结构组成的无界阻塞TransferQueue队列。
tryTransfer方法。则是用来试探下生产者传入的元素是否能直接传给消费者。若是没有消费者等待接收元素,则返回false。和transfer方法的区别是tryTransfer方法不管消费者是否接收,方法当即返回。而transfer方法是必须等到消费者消费了才返回。
对于带有时间限制的tryTransfer(E e, long timeout, TimeUnit unit)方法,则是试图把生产者传入的元素直接传给消费者,可是若是没有消费者消费该元素则等待指定的时间再返回,若是超时还没消费元素,则返回false,若是在超时时间内消费了元素,则返回true。
一个基于已连接节点的、任选范围的阻塞双端队列。
Integer.MAX_VALUE
。只要插入元素不会使双端队列超出容量,每次插入后都将动态地建立连接节点。remove
、removeFirstOccurrence
、removeLastOccurrence
、contains
、iterator.remove()
以及批量操做,它们均以线性时间运行。