一、Queue

Queye接口体系图

体系分析

Deque实现类:ArrayDequeLinkedList(数组和链表实现双向队列)

BlockingDeque实现类:LinkedBlockingDeque(链表实现阻塞双向队列)

BlockingQueue实现类:ArrayBlockingQueue,LinkedBlockingQueue,PriorityBlockingQueue,SynchronousQueue,DelayQueue

Queue源码

public interface Queue<E> extends Collection<E> {  //jdk1.5
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
}

在处理元素前用于保存元素的 collection.除了基本的 Collection 操作外,队列还提供其他的插入、提取和检查操作.每个方法都存在两种形式:一种抛出异常(操作失败时),另一种返回一个特殊值(nullfalse,具体取决于操作).插入操作的后一种形式是用于专门为有容量限制的 Queue 实现设计的;在大多数实现中,插入操作不会失败.

Queue 接口并未定义阻塞队列的方法,而这在并发编程中是很常见的.BlockingQueue 接口定义了那些等待元素出现或等待队列中有可用空间的方法,这些方法扩展了此接口.

二、Deque

一个线性 collection,支持在两端插入和移除元素.名称 deque 是“double ended queue(双端队列)”的缩写.

此接口定义在双端队列两端访问元素的方法.提供插入、移除和检查元素的方法.每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(nullfalse,具体取决于操作).插入操作的后一种形式是专为使用有容量限制的 Deque 实现设计的;在大多数实现中,插入操作不能失败.

下表总结了上述 12 种方法:

此接口扩展了 Queue 接口.在将双端队列用作队列时,将得到 FIFO(先进先出)行为.将元素添加到双端队列的末尾,从双端队列的开头移除元素.从 Queue 接口继承的方法完全等效于 Deque 方法,如下表所示:

双端队列也可用作 LIFO(后进先出)堆栈.应优先使用此接口而不是遗留 Stack 类.在将双端队列用作堆栈时,元素被推入双端队列的开头并从双端队列开头弹出.堆栈方法完全等效于 Deque 方法,如下表所示:

此接口提供了两种移除内部元素的方法:removeFirstOccurrenceremoveLastOccurrence.注意,在将双端队列用作队列或堆栈时,peek 方法同样正常工作;无论哪种情况下,都从双端队列的开头抽取元素.

三、BlockingQueue

支持两个附加操作的 Queue,这两个操作是:获取元素时等待队列变为非空,以及存储元素时等待空间变得可用.

BlockingQueue 方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(nullfalse,具体取决于操作),第三种是在操作可以成功前,无限期地阻塞当前线程,第四种是在放弃前只在给定的最大时间限制内阻塞.下表中总结了这些方法:

BlockingQueue 实现是线程安全的,实现主要用于生产者-消费者队列,以下是基于典型的生产者-使用者场景的一个用例:

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();
}
}

改写之前的消费者生产者模式

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; class Product{
int id;
Product(int id){
this.id=id;
}
@Override
public String toString() {
return super.toString();
}
}
class Productor implements Runnable{
BlockingQueue<Product> blockingQueue = null;
public Productor(BlockingQueue<Product> blockingQueue ) {
this.blockingQueue=blockingQueue;
}
@Override
public void run() {
for(int i=;i<;i++){
Product p =new Product(i);
try {
blockingQueue.put(p);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"生成了一个"+p);
}
}
}
class Comsumer implements Runnable{
BlockingQueue<Product> blockingQueue = null;
public Comsumer(BlockingQueue<Product> blockingQueue ) {
this.blockingQueue=blockingQueue;
}
@Override
public void run() {
Product p=null;
for(;;){
try {
p = blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"消费了一个"+p);
}
}
} public class TestBlockingQueue {
public static void main(String[] args) {
BlockingQueue<Product> b = new LinkedBlockingQueue<Product>();
Productor p = new Productor(b);
Comsumer c = new Comsumer(b);
new Thread(p).start();
new Thread(p).start();
new Thread(c).start();
new Thread(c).start();
}
}

四、ArrayBlockingQueue

一个由数组支持的有界阻塞队列,构造方法必须定义确定大小的队列,此队列按 FIFO(先进先出)原则对元素进行排序.队列的头部 是在队列中存在时间最长的元素.队列的尾部 是在队列中存在时间最短的元素.新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素.

这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素.一旦创建了这样的缓存区,就不能再增加其容量.试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞.

ArrayBlockingQueue中的方法基本都使用了同步,例生产者消费者的底层代码:

final Object[] items;
final ReentrantLock lock;
private final Condition notEmpty;
private final Condition notFull;
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();
}
private void enqueue(E x) {
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
notEmpty.signal();
}
private E dequeue() {
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;
}
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();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}

五、LinkedBlockingQueue

一个基于已链接节点的、范围任意的 blocking queue.此队列按 FIFO(先进先出)排序元素.队列的头部 是在队列中时间最长的元素.队列的尾部 是在队列中时间最短的元素.新元素插入到队列的尾部,并且队列获取操作会获得位于队列头部的元素.链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低.

可选的容量范围构造方法参数作为防止队列过度扩展的一种方法.如果未指定容量,则它等于 Integer.MAX_VALUE.除非插入节点会使队列超出容量,否则每次插入后会动态地创建链接节点.例其中一个方法:

static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
private void enqueue(Node<E> node) {
last = last.next = node;
}
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();
}

PriorityQueue一个基于优先级无界优先级队列.优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的Comparator进行排序,具体取决于所使用的构造方法.

PriorityBlockingQueue一个无界阻塞队列,它使用与类 PriorityQueue 相同的顺序规则,并且提供了阻塞获取操作.

LinkedBlockingDeque一个基于已链接节点的、任选范围的阻塞双端队列

SynchronousQueue每个插入操作必须等待另一个线程的对应移除操作.

DelayQueue个无界阻塞队列,只有在延迟期满时才能从中提取元素.

注:1.以上所有队列都不能插入null元素,因为很多方法的返回值是null.

2.队列与List接口不同,此接口不支持通过索引访问元素.队列只能从头部和尾部获取元素.

javase(12)_集合框架_Queue的更多相关文章

  1. javase(8)_集合框架_List、Set、Map

    一.集合体系(不包括Queue体系) 二.ArrayList ArrayList的属性 private transient Object[] elementData; //存储元素 private i ...

  2. JavaSE中Collection集合框架学习笔记(2)——拒绝重复内容的Set和支持队列操作的Queue

    前言:俗话说“金三银四铜五”,不知道我要在这段时间找工作会不会很艰难.不管了,工作三年之后就当给自己放个暑假. 面试当中Collection(集合)是基础重点.我在网上看了几篇讲Collection的 ...

  3. JavaSE中Collection集合框架学习笔记(3)——遍历对象的Iterator和收集对象后的排序

    前言:暑期应该开始了,因为小区对面的小学这两天早上都没有像以往那样一到七八点钟就人声喧闹.车水马龙. 前两篇文章介绍了Collection框架的主要接口和常用类,例如List.Set.Queue,和A ...

  4. JavaSE学习总结第15天_集合框架1

      15.01 对象数组的概述和使用 public class Student { // 成员变量 private String name; private int age; // 构造方法 publ ...

  5. JavaSE学习总结第18天_集合框架4

      18.01 Map集合概述和特点 Map接口概述:将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值 Map接口和Collection接口的不同 1.Map是双列的,Coll ...

  6. Java之旅_高级教_集合框架

    摘自:http://www.runoob.com/java/java-collections.html Java 集合框架 早在Java2之前,java 就提供了特设类.比如:Dictionary,V ...

  7. JavaSE复习_9 集合框架复习

    △列表迭代器也是不支持在迭代的时候添加元素的,只是列表迭代器自己定义了增删的方法而已.迭代器可以看成实在两个元素之间的指针,每当调用next就跳过一个元素并返回刚刚跳过的元素. △HashTable不 ...

  8. java oop第07章_集合框架

    一. 什么是集合: 在Java中提供了一些可以保存同一数据类型的数据集称为集合,就是规定了一些集合的规范(接口.抽象类.实现类)及方法, 方便我们程序在保存数据时进行增.删.改.查操作,编程更加高效. ...

  9. JavaSE学习总结第16天_集合框架2

      16.01 ArrayList存储字符串并遍历 ArrayList类概述:底层数据结构是数组,查询快,增删慢,线程不安全,效率高 ArrayList类是List 接口的大小可变数组的实现.实现了所 ...

随机推荐

  1. Mecanim Control

    http://www.ufe3d.com/doku.php/mecanimcontrol Mecanim Control Your ultimate solution for Mecanim base ...

  2. 自定义Mybatis返回类型及注意事项

    一.自定义返回拦截器package com.yaoex.crm.service.util; import org.apache.ibatis.session.ResultContext;import ...

  3. poj3276 Face The Right Way

    Face The Right Way POJ - 3276 题目大意: n头牛排成一列,每头牛向前或向后,为了让所有牛都面向前方,设定一个k值,每操作一次恰好使k头连续的牛转向,求最少的操作次数m和对 ...

  4. C# string.Compare()

    tring.Compare方法,用来比较2个字符串值得大小 string.Compare(str1, str2, true); 返回值: 1 : str1大于str2 0 : str1等于str2 - ...

  5. JS面向对象方法(一): 使用原生JS 实现导航栏下多级分类弹出效果

    利用二级菜单的onmouseover/out事件 重新构建一级菜单 ".hover" 样式类 代码如下: CSS部分: 在原来的目标:hover样式中 增加 .hover状态 li ...

  6. redis开发小结

    随着缓存在web服务中用的越来越广泛,redis可以说成为了目前最流行的NoSQL数据库!redis与memcached最大的不同在于redis支持更多的数据类型,包括string.hash.list ...

  7. [软件工程基础]PhyLab 功能规格说明书

    前言 Sigma 团队想要在 PhyLab 上做的增量改进见需求分析.六个功能中只有题库和图文流程需要对界面进行大的改动,剩下的功能在用户看来仅仅是在原有界面上有内容上的扩充,因此不在功能规格说明书的 ...

  8. 洛谷1941(dp)

    常规的dp,当前有值且碰不到管子就转移,可以连跳的操作我就加了一维表示当前是不是连跳过来的.第二问前缀和即可得(不对啊边走边记录就行了吧我冗了Orz). #include <cstdio> ...

  9. GDB 格式化结构体输出

    转载:http://blog.csdn.net/unix21/article/details/9991925 set print addressset print address on打开地址输出,当 ...

  10. 牛客网Java刷题知识点之Java集合类里面最基本的接口有哪些

    不多说,直接上干货! https://www.nowcoder.com/ta/review-java/review?tpId=31&tqId=21086&query=&asc= ...