一、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. IT兄弟连 JavaWeb教程 Servlet会话跟踪 创建Cookie

    Tomcat作为Web服务器,对Cookie提供了良好的支持.那么,运行在Tomcat的Servlet该如何访问Cookie呢?幸运的是,Servlet无需直接和HTTP请求或响应中的原始Cookie ...

  2. ISCC 2018线上赛 writeup

    今天有机会去ISCC2018参加了比赛,个人的感受是比赛题目整体难度不高,就是脑洞特别大,flag形式不明确,拿到flag后也要猜测flag格式,贼坑 废话不多说,以下是本人的解题思路 MISC 0x ...

  3. adb server version (39) doesn't match this client (40); killing...

    在启动RN项目的时候也报错,上面的错误是在adb的环境变量中的位置和android studio的sdk不是一个位置.adb是在sdk中的,所以他们应该是一致的位置 android studio的sd ...

  4. E. Cyclic Components (DFS)(Codeforces Round #479 (Div. 3))

    #include <bits/stdc++.h> using namespace std; *1e5+; vector<int>p[maxn]; vector<int&g ...

  5. 浅谈算法——AC自动机

    在学习AC自动机之前,你需要两个前置知识:Trie树,KMP 首先我们需要明白,AC自动机是干什么的(用来自动AC的) 大家都知道KMP算法是求单字符串对单字符串的匹配问题的,那么多字符在单字符上匹配 ...

  6. [已读]你不知道的JavaScript(上卷)

    就在前幾天,我在看完第一部分的時候,說它在我心中要超過蝴蝶書了,好吧,現在要收回這句話.第二部分的內容著重在ecma5,6對象的新特性的介紹,深度上就一般啦,沒什麼收穫.總體來說,這本書詞法作用域,作 ...

  7. audio、video的控制

    W3C上面给的是js控制相关的播放与暂停,不过在实际开发中我们多会选择JQ来操作的,毕竟方便很多,而play()和pause()用于js play并不是jQuery的函数,而是DOM元素的函数,所以我 ...

  8. jquery.validate自定义验证--成功提示与择要提示

    1. 自定义验证--成功提示 1) 添加选项 errorClass: "unchecked", validClass: "checked", errorElem ...

  9. linux学习-Linux系统启动过程

    linux系统启动过程 Linux系统的启动过程并不是大家想象中的那么复杂,其过程可以分为5个阶段: 内核的引导. 运行init. 系统初始化. 建立终端 . 用户登录系统. 内核引导 电源开机后,首 ...

  10. (wp8.1开发)触摸键从推出变返回

    ---恢复内容开始--- 今天开发wp8.1,遇到这样一个问题,从第一个页面跳到第二个页面,在第二个页面按返回,结果程序退出了.原来是系统把返回键定义成退出了. 解决办法: 在第一个页面加入如下代码 ...