队列queue

简介: 队列queue

一.Queue 介绍

1.Queue 的介绍

Queue,中文名叫队列,无论现实生活中还是计算机的世界中,都是一个很重要的角色哦~

Queue 是一种数据结构,大家可以把我想象成一个数组,元素从我的一头进入、从另外一头出去,称为 FIFO 原则(先进先出原则)。

Queue 有两个亲兄弟:List(列表)、Set(集),他们都是Collection的儿子,Queue 还有一个远房亲戚:Map(映射)。他们都是java.util包这个大家庭的成员哦~

2.队列类图

18 个 Queue 的继承实现关系图

  • Queue接口继承Collection接口,Collection接口继承Iterable接口
  • BlockingQueue接口、Deque接口 继承Queue接口
  • AbstractQueue抽象类实现Queue接口
  • BlockingDeque接口、TransferQueue接口继承BlockingQueue接口
  • BlockingDeque接口继承Deque接口
  • LinkedBlockingDeque实现BlockingDeque接口
  • LinkedTransferQueue类接口实现TransferQueue接口
  • LinkedList类、ArrayDeque类、ConcurrentLinkedDeque实现Deque接口
  • ArrayBlockingQueue类、LinkendBlockingQueue类、LinkedBlockingDeque类、LinkedTransferQueue类、SynchronousQueue类、PriorityBlockQueue类、DelayQueue类继承AbstractQueue抽象类和实现了 BlockingQueue 接口
  • PriorityQueue类和ConcurrentLinkedQueue继承AbstractQueue抽象类

注意:

  • Deque:全称 Double-Ended queue,表示双端队列。
  • 类实现接口,用 implements
  • 接口继承接口,用 extends
  • 类继承类,用 extends

3.Queue 的核心方法

  • add
  • element
  • offer
  • peek
  • poll
  • remove

Queue的核心方法:

动作 抛异常 返回特殊值
Insert add(e) offer(e)
Remove remove() poll
Examine element() peek()
  • 比如添加(Insert)元素的动作,会有两种方式:add(e)offer(e)。如果调用 add(e)方法时,添加失败,则会抛异常,而如果调用的是 offer(e)方法失败时,则会返回false。offer 方法用于异常是正常的情况下使用,比如在有界队列中,优先使用 offer 方法。假如队列满了,不能添加元素,offer 方法返回 false,这样我们就知道是队列满了,而不是去 handle 运行时抛出的异常。
  • 同理,移除(Remove)元素的动作,队列为空时,remove 方法抛异常,而 poll 返回 null。如果移除头部的元素成功,则返回移除的元素。
  • 同理,检测(Examine)元素的动作,返回头部元素(最开始加入的元素),但不删除元素, 如果队列为空,则 element()方法抛异常,而 peek()返回 false。
  • Queue 接口没有定义阻塞队列的方法,这些方法在 BlockQueue 接口中定义了。
  • Queue 实现类通常不允许插入 null 元素,尽管一些实现类比如 LinkedList 不禁止插入 null,但是还是不建议插入 null,因为 null 也被用在 poll 方法的特殊返回值,以说明队列不包含元素。

4.Queue 的实现类

5.常见 Queue 说明

二.Deque 接口

1.什么是 Deque?

Queue 以及 Deque 都是继承于 Collection,Deque 是 Queue 的子接口。双端队列,可以在首尾插入或删除元素。

Deque 中直接子类有两个:LinkedList 以及 ArrayDeque。

ArrayDeque 是无初始容量的双端队列,LinkedList 则是双向链表。而我们还能看到,ArrayDeque 作为队列时的效率比 LinkedList 要高,而在栈的使用场景下,无疑具有尾结点不需判空的 LinkedList 较高效。

ArrayDeque 通常作为栈或队列使用,但是栈的效率不如 LinkedList 高。LinkedList 通常作为栈或队列使用,但是队列的效率不如 ArrayQueue 高。

2.双端可用 Deque 接口

Deque 概念: 支持两端元素插入和移除的线性集合。名称deque是双端队列的缩写,通常发音为deck。大多数实现 Deque 的类,对它们包含的元素的数量没有固定的限制的,支持有界和无界。

3.Deque 方法

4.Deque 和 Queue 比较

作为 FIFO 时等价于 Queue 的方法如下表所示:

比如 Queue 的 add 方法和 Deque 的 addLast 方法等价。

5.Deque 和 Stack 比较

  • Deque 也可以用作 LIFO(后进先出)栈,这个接口优于传统的 Stack 类。当作为栈使用时,元素被 push 到 deque 队列的头,而 pop 也是从队列的头 pop 出来。
  • Stack(栈)的方法正好等同于 Deque 的如下方法:

注意:peek 方法不论是作为栈还是队列,都是从队列的检测队列的头,返回最先加入的元素。比如第一次 put 100,第二次 put 200,则 peek 返回的是 100。

6.Deque 的实现与继承

哪些类实现了Deque接口:

  • LinkedList 类
  • ArrayDeque 类
  • ConcurrentLinkedDeque 类
  • LinkedBlockingDeque 类

哪些类继承了Deque接口:

  • BlockingDeque 接口

public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {}

三.AbstractQueue 类

1.AbstractQueue 类介绍

AbstractQueue 是一个抽象类,实现了 Queue 接口,提供了一些 Queue 操作的骨架实现。

public abstract class AbstractQueue<E>

   extends AbstractCollection<E>

   implements Queue<E> {

}

2.AbstractQueue 的方法

  • add
  • addAll
  • clear
  • element
  • remove

方法 add、remove、element 方法基于 offer、poll 和 peek。也就是说如果不能正常操作,则抛出异常。

public boolean add(E e) {

       if (offer(e))

           return true;

       else

           throw new IllegalStateException("Queue full");

}

如果继承 AbstractQueue 抽象类则必须保证 offer 方法不允许 null 值插入。

3.AbstractQueue 的继承

哪些类继承了 AbstractQueue 抽象类:

  • ArrayBlockingQueue
  • LinkendBlockingQueue
  • LinkedBlockingDeque
  • LinkedTransferQueue
  • SynchronousQueue
  • PriorityBlockQueue
  • DelayQueue
  • PriorityQueue
  • ConcurrentLinkedQueue

四.BlockingQueue 接口

1.BlockingQueue 接口定义

阻塞队列:

  • BlockQueue 满了,PUT 操作被阻塞
  • BlockQueue 为空,Take 操作被阻塞

阻塞队列为空的情况:

  1. BlockingQueue(阻塞队列)也是一种队列,支持阻塞的插入和移除方法。
  2. 阻塞的插入:当队列满时,队列会阻塞插入元素的线程,直到队列不满。
  3. 阻塞的移除:当队列为空,获取元素的线程会等待队列变为非空。
  4. 应用场景:生产者和消费者,生产者线程向队列里添加元素,消费者线程从队列里移除元素,阻塞队列时获取和存放元素的容器。
  5. 为什么要用阻塞队列:生产者生产和消费者消费的速率不一样,需要用队列来解决速率差问题,当队列满了或空的时候,则需要阻塞生产或消费动作来解决队列满或空的问题。

2.BlockingQueue 核心方法

BlockingQueue 接口的 10 个核心方法:

3.十个核心方法总结如下

BlockingQueue接口的10个核心方法:

有三大类操作:插入、移除、检查。

  • 插入有四种方法: add、offer、put、offer 超时版。
  • IllegalStateException - 队列满了
  • ClassCastException - 添加的元素类型不匹配
  • NullPointerException - 添加的元素为 null
  • IllegalArgumentException - 添加的元素某些属性不匹配
  • add 方法特别之处用于添加失败时抛出异常,共有四种异常:
  • offer 方法特别之处用于添加失败时只返回 false
  • put 方法特别之处用于当阻塞队列满时,生产者如果往队列里 put 元素,则队列会一直阻塞生产者线程,直到队列可用或者响应中断退出
  • offer 超时方法特别之处用于当阻塞队列满时,生产者如果往队列里面插入元素,队列会阻塞生产者线程一段时间,如果超过了指定时间,生产者线程会退出,并返回 false。
  • 移除有四种方法: remove、poll、take、poll 超时版
  • NoSuchElementException - 如果这个队列是空的
  • remove 方法特别之处用于移除失败时抛出异常
  • poll 方法特别之处用于移除失败时返回 null
  • take 方法特别之处用于当阻塞队列为空时,消费者线程如果从队列里面移除元素,则队列会一直阻塞消费者线程,直到队列不为空
  • poll 超时方法特别之处用于当阻塞队列空时,消费者如果从队列里面删除元素,则队列会一直阻塞消费者线程,如果超过了指定时间,消费者线程会退出,并返回 null
  • 检查有两种方法: element、peek
  • element 方法用于检测头部元素的存在性,如果队列为空,则抛出异常,否则返回头部元素。
  • peek 方法用于检测头部元素的存在性,如果队列为空,返回特殊值 null,否则返回头部的元素。

4.BlockingQueue 原理

BlockingQueue 通过什么来阻塞插入和移除的?

  • 当往队列里插入一个元素时,如果队列不可用,那么阻塞生产者主要通过 LockSupport. park(this)来实现。
  • park 这个方法会阻塞当前线程,只有以下 4 种情况中的一种发生时,该方法才会返回。
  • 与 park 对应的 unpark 执行或已经执行时。“已经执行”是指 unpark 先执行,然后再执行 park 的情况。
  • 线程被中断时。
  • 等待完 time 参数指定的毫秒数时。
  • 异常现象发生时,这个异常现象没有任何原因。

5.BlockingQueue 继承与实现

哪些类继承了BlockingQueue接口:

  • BlockingDeque 接口 - 双端阻塞队列
  • TransferQueue 接口 - 传输队列

哪些类实现了BlockingQueue接口:

  • ArrayBlockingQueue 类 - 由数组构成的有界阻塞队列
  • LinkedBlockingQueue 类 - 由链表构成的有界阻塞队列,界限默认大小为 Integer.MAX_Value(2^31-1),值非常大,相当于无界。
  • LinkedBlockingDeque 类 - 由链表构成的双向阻塞队列
  • LinkedTransferQueue 类 - 由链表构成的无界阻塞队列
  • SynchronousQueue 类 - 不存储元素的阻塞队列,只有一个元素进行数据传递。
  • LinkedTransferQueue 类 - 由链表构成的无界阻塞 TransferQueue 队列
  • DelayQueue 类 - 使用优先级队列实现的延迟无界阻塞队列

6.BlockingDeque 接口方法

是阻塞队列BlockingQueue和双向队列Deque接口的结合。有如下方法:

BlockingQueue和BlockingDeque的对等方法:

五.TransferQueue 接口

1.TransferQueue 简介

如果有消费者正在获取元素,则将队列中的元素传递给消费者。如果没有消费者,则等待消费者消费。我把它称作使命必达队列,必须将任务完成才能返回。

2.理解三个方法

针对TransferQueue的transfer方法:圆通快递员要将小明的 2 个快递送货到门,韵达快递员也想将小明的 2 个快递送货到门。小明一次只能拿一个,快递员必须等小明拿了一个后,才能继续给第二个。

针对TransferQueue的tryTransfer方法:圆通快递员要将小明的 2 个快递送货到门,韵达快递员也想将小明的 2 个快递送货到门。发现小明不在家,就把快递直接放到菜鸟驿站了。

针对TransferQueue的tryTransfer超时方法:圆通快递员要将小明的 2 个快递送货到门,韵达快递员也想将小明的 2 个快递送货到门。发现小明不在家,于是先等了 5 分钟,发现小明还没有回来,就把快递直接放到菜鸟驿站了。

3.TransferQueue 的原理解析

transfer方法的原理:

  • 原理图解释:生产者线程 Producer Thread 尝试将元素 B 传给消费者线程,如果没有消费者线程,则将元素 B 放到尾节点。并且生产者线程等待元素 B 被消费。当元素 B 被消费后,生产者线程返回。
  • 如果当前有消费者正在等待接收元素(消费者通过 take 方法或超时限制的 poll 方法时),transfer 方法可以把生产者传入的元素立刻 transfer(传输)给消费者。
  • 如果没有消费者等待接收元素,transfer 方法会将元素放在队列的 tail(尾)节点,并等到该元素被消费者消费了才返回。

tryTransfer(E e)

  • 试探生产者传入的元素是否能直接传给消费者。
  • 如果没有消费者等待接收元素,则返回 false。
  • 和 transfer 方法的区别是,无论消费者是否接收,方法立即返回。

tryTransfer(E e, long timeout, TimeUnit unit)

  • 带有时间限制的 tryTransfer 方法。
  • 试图把生产者传入的元素直接传给消费者。
  • 如果没有消费者消费该元素则等待指定的时间再返回。
  • 如果超时了还没有消费元素,则返回 false。
  • 如果在超时时间内消费了元素,则返回 true。

getWaitingConsumerCount()

  • 获取通过 BlockingQueue.take()方法或超时限制 poll 方法等待接受元素的消费者数量。近似值。
  • 返回等待接收元素的消费者数量。

hasWaitingConsumer()

  • 获取是否有通过 BlockingQueue.tabke()方法或超时限制 poll 方法等待接受元素的消费者。
  • 返回 true 则表示至少有一个等待消费者。

4.TransferQueue 接口实现与继承

TransferQueue接口继承了哪些接口:

  • BlockingQueue 接口,可作为阻塞队列使用
  • Queue 接口,可作为队列使用

哪些类实现了TransferQueue接口:

  • LinkedTranferQueue 接口

六.PriorityQueue 类

1.什么是 PriorityQueue?

队列是遵循先进先出(First-In-First-Out)模式的,但有时需要在队列中基于优先级处理对象。

Queue 有一个直接子类 PriorityQueue

PriorityQueue 是基于优先堆的一个无界队列,这个优先队列中的元素可以默认自然排序或者通过提供的 Comparator(比较器)在队列实例化的时排序。

  • 优先队列的头是基于自然排序或者 Comparator 排序的最小元素。如果有多个对象拥有同样的排序,那么就可能随机地取其中任意一个。当我们获取队列时,返回队列的头对象。
  • 优先队列的大小是不受限制的,但在创建时可以指定初始大小。当我们向优先队列增加元素的时候,队列大小会自动增加。
  • PriorityQueue 是非线程安全的,所以 Java 提供了 PriorityBlockingQueue(实现 BlockingQueue 接口)用于 Java 多线程环境。

PriorityQueue 的底层数据结构是数组,而无边界的形容,那么指明了 PriorityQueue 是自带扩容机制的,具体请看 PriorityQueue 的 grow 方法。

PriorityQueue 可以作为堆使用,而且可以根据传入的 Comparator 实现大小的调整,会是一个很好的选择。

2.PriorityQueue 特点

按照自定义优先级排序

  • PriorityQueue 是一个支持优先级的无界阻塞队列;
  • 默认自然顺序升序排序;
  • 可以通过构造参数 Comparator 来对元素进行排序;
  • 自定义实现 comapreTo()方法来指定元素排序规则。
  • 不允许插入 null 元素。
  • 实现 PriorityQueue 接口的类,不保证线程安全,除非是 PriorityBlockingQueue。
  • PriorityQueue 的迭代器不能保证以任何特定顺序遍历元素,如果需要有序遍历,请考虑使用Arrays.sort(pq.toArray)
  • 进列(offeradd)和出列( pollremove())的时间复杂度 O(log(n))。
  • remove(Object) 和 contains(Object)的算法时间复杂度 O(n)。
  • peek、element、size 的算法时间复杂度为 O(1)。

public PriorityQueue(Comparator<? super E> comparator) {

    this(DEFAULT_INITIAL_CAPACITY, comparator);

}

3.PriorityQueue 继承与实现

PriorityQueue类继承了哪些类:

  • AbstractQueue 抽象类,具有队列的功能

PriorityQueue类实现了哪些接口:

  • Queue 接口,可作为队列使用。

七.并发安全 Queue

1.ConcurrentLinkedQueue 图解

2.ConcurrentLinkedQueue 原理

  • ConcurrentLinked 是由链表结构组成的线程安全的先进先出无界队列。
  • 当多线程要共享访问集合时,ConcurrentLinkedQueue 是一个比较好的选择。
  • 不允许插入 null 元素
  • 支持非阻塞地访问并发安全的队列,不会抛出 ConcurrentModifiationException 异常。
  • size 方法不是准确的,因为在统计集合的时候,队列可能正在添加元素,导致统计不准。
  • 批量操作 addAll、removeAll、retainAll、containsAll、equals 和 toArray 不保证原子性(操作不可分割)
  • 添加元素 happen-before 其他线程移除元素。

用法如下:

ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();

BuildingBlockWithName buildingBlock = new BuildingBlockWithName("三角形", "A");

concurrentLinkedQueue.add(buildingBlock);

继承与实现

ConcurrentLinkedQueue 类继承了哪些类

  • AbstractQueue 抽象类,具有队列的功能

ConcurrentLinkedQueue 类实现了哪些接口

  • Queue 接口,可作为队列使用

3.ConcurrentLinkedDeque 类

ConcurrentLinkedDeque原理图:

  • 由链表结构组成的双向无界阻塞队列
  • 插入、删除和访问操作可以并发进行,线程安全的类
  • 不允许插入 null 元素
  • 在并发场景下,计算队列的大小是不准确的,因为计算时,可能有元素加入队列。
  • 批量操作 addAll、removeAll、retainAll、containsAll、equals 和 toArray 不保证原子性(操作不可分割)

使用:

BuildingBlockWithName buildingBlock1 = new BuildingBlockWithName("三角形", "A");

BuildingBlockWithName buildingBlock2 = new BuildingBlockWithName("四边形", "B");

ConcurrentLinkedDeque concurrentLinkedDeque = new ConcurrentLinkedDeque();

concurrentLinkedDeque.addFirst(buildingBlock1);

concurrentLinkedDeque.addLast(buildingBlock2);

//结果:顺序:三角形、四边形

4.ArrayBlockingQueue 类

ArrayBlockingQueuey原理:

  • ArrayBlockingQueue 是一个用数组实现的有界阻塞队列。
  • 队列慢时插入操作被阻塞,队列空时,移除操作被阻塞。
  • 按照先进先出(FIFO)原则对元素进行排序。
  • 默认不保证线程公平的访问队列。
  • 公平访问队列:按照阻塞的先后顺序访问队列,即先阻塞的线程先访问队列。
  • 非公平性是对先等待的线程是非公平的,当队列可用时,阻塞的线程都可以争夺访问队列的资格。有可能先阻塞的线程最后才访问访问队列。
  • 公平性会降低吞吐量。

使用:

创建两个积木:三角形、四边形,然后添加到队列:

BuildingBlockWithName buildingBlock1 = new BuildingBlockWithName("三角形", "A");

BuildingBlockWithName buildingBlock2 = new BuildingBlockWithName("四边形", "B");

ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(100, true);

arrayBlockingQueue.add(buildingBlock1);

arrayBlockingQueue.add(buildingBlock2);

5.LinkedBlockingQueue 类

LinkedBlockingQueue原理:

  • LinkedBlockingQueue 具有单链表和有界阻塞队列的功能。
  • 队列慢时插入操作被阻塞,队列空时,移除操作被阻塞。
  • 默认和最大长度为 Integer.MAX_VALUE,相当于无界(值非常大:2^31-1)。

LinkedBlockingQueue的应用场景:

  • 吞吐量通常要高于 ArrayBlockingQueue。创建线程池时,参数 runnableTaskQueue(任务队列),用于保存等待执行的任务的阻塞队列可以选择 LinkedBlockingQueue。静态工厂方法 Executors.newFixedThreadPool()使用了这个队列。

LinkedBlockingQueue实现了哪些接口:

  • LinkedBlockingQueue 继承了 BlockingQueue 类,可作为阻塞队列使用
  • LinkedBlockingQueue 继承了 AbstractQueue 抽象类,具有队列的功能。
  • LinkedBlockingQueue 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。

6.LinkedBlockingDeque 类

LinkedBlockingDeque原理:

  • 由链 LinkedBlockingDeque = 阻塞队列+链表+双端访问
  • 线程安全。
  • 多线程同时入队时,因多了一端访问入口,所以减少了一半的竞争。
  • 默认容量大小为 Integer.MAX_VALUE。可指定容量大小。

LinkedBlockingDeque的应用场景:

LinkedBlockingDeque 可以用在“工作窃取“模式中。

工作窃取算法:某个线程比较空闲,从其他线程的工作队列中的队尾窃取任务来帮忙执行。

LinkedBlockingDeque实现了哪些接口:

  • LinkedBlockingDeque 继承了 BlockingDeque 类,可作为阻塞队列使用
  • LinkedBlockingDeque 继承了 AbstractQueue 抽象类,具有队列的功能。
  • LinkedBlockingDeque 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。

7.PriorityBlockingQueue 类

PriorityBlockQueue的原理:

  • PriorityBlockQueue = PriorityQueue + BlockingQueue
  • 之前我们也讲到了 PriorityQueue 的原理,支持对元素排序。
  • 元素默认自然排序。
  • 可以自定义 CompareTo()方法来指定元素排序规则。
  • 可以通过构造函数构造参数 Comparator 来对元素进行排序。

PriorityBlockQueue实现了哪些接口:

  • LinkedBlockingQueue 继承了 BlockingQueue 接口,可作为阻塞队列使用
  • LinkedBlockingQueue 继承了 AbstractQueue 抽象类,具有队列的功能。
  • LinkedBlockingQueue 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。

八.其他 Queue

1.ArrayDeque 类

特点:

  • 由数组组成的双端队列。
  • 没有容量限制,根据需要扩容。
  • 不是线程安全的。
  • 禁止插入 null 元素。
  • 当用作栈时,比栈速度快,当用作队列时,速度比 LinkList 快。
  • 大部分方法的算法时间复杂度为 O(1)。
  • remove、removeFirstOccurrence、removeLastOccurrence、contains、remove 和批量操作的算法时间复杂度 O(n)

使用:

ArrayDeque arrayDeque = new ArrayDeque();

for (int i = 0; i < 50; i++) {

   arrayDeque.add(buildingBlock); // add方法等价于addLast方法

}

2.LinkedTransferQueue 类

LinkedTransferQueue原理:

LinkedTransferQueue = 阻塞队列+链表结构+TransferQueue

之前我们讲“使命必达 TransferQueue 接口时已经介绍过了 TransferQueue 接口 ,所以 LinkedTransferQueue 接口跟它相似,只是加入了阻塞插入和移除的功能,以及结构是链表结构。

之前的 TransferQueue 也讲到了 3 个案例来说明 TransferQueue 的原理,大家可以回看 TransferQueue。

LinkedTransferQueue接口比其他阻塞队列多了5个方法:

  • transfer(E e)
  • tryTransfer(E e)
  • tryTransfer(E e, long timeout, TimeUnit unit)
  • getWaitingConsumerCount()
  • hasWaitingConsumer()

LinkedTransferQueue实现了哪些接口:

  • LinkedBlockingDeque 继承了 BlockingQeque 类,可作为阻塞队列使用
  • LinkedBlockingDeque 继承了 AbstractQueue 抽象类,具有队列的功能

3.SynchronousQueue 类

SynchronousQueue原理:

  • 我称 SynchronousQueue 为”传球好手“。想象一下这个场景:小明抱着一个篮球想传给小花,如果小花没有将球拿走,则小明是不能再拿其他球的。
  • SynchronousQueue 负责把生产者产生的数据传递给消费者线程。
  • SynchronousQueue 本身不存储数据,调用了 put 方法后,队列里面也是空的。
  • 每一个 put 操作必须等待一个 take 操作完成,否则不能添加元素。
  • 适合传递性场景。
  • 性能高于 ArrayBlockingQueue 和 LinkedBlockingQueue。

SynchronousQueue应用场景:

  • 吞吐量通常要高于 LinkedBlockingQueue。创建线程池时,参数 runnableTaskQueue(任务队列),用于保存等待执行的任务的阻塞队列可以选择 SynchronousQueue。静态工厂方法 Executors.newCachedThreadPool()使用了这个队列

SynchronousQueue和LinkedTransferQueue的区别:

  • SynchronousQueue 不存储元素,而 LinkedTransferQueue 存储元素。
  • SynchronousQueue 队列里面没有元素,而 LinkedTransferQueue 可以有多个存储在队列等待传输。
  • LinkedTransferQueue 还支持若传输不了,则丢到队列里面去。
  • LinkedTransferQueue 还支持若超过一定时间传输不了,则丢到队列里面去。

4.DelayQueue 类

DelayQueue原理:

  • DelayQueue = Delayed + BlockingQueue。队列中的元素必须实现 Delayed 接口。
  • 在创建元素时,可以指定多久可以从队列中获取到当前元素。只有在延时期满才能从队列中获取到当前元素。

public class DelayQueue<E extends Delayed> extends AbstractQueue<E>

   implements BlockingQueue<E> {

源码解析:

  • 添加元素时,指定延时多久可以从队列中获取元素

public boolean offer(E e, long timeout, TimeUnit unit) {

   return offer(e);

}

  • 获取元素的方法 poll 需要等待延时时间过了才能获取到元素

if (first == null || first.getDelay(NANOSECONDS) > 0)

   return null;

else

   return q.poll();

应用场景:

  • 缓存系统的设计:可以用 DelayQueue 保存缓存元素的有效期。然后用一个线程循环的查询 DelayQueue 队列,一旦能从 DelayQueue 中获取元素时,表示缓存有效期到了。
  • 定时任务调度:使用 DelayQueue 队列保存当天将会执行的任务和执行时间,一旦从 DelayQueue 中获取到任务就开始执行。比如 Java 中的 TimerQueue 就是使用 DelayQueue 实现的。

DelayQueue实现了哪些接口:

  • DelayQueue 实现了 BlockingQueue 接口,可作为阻塞队列使用
相关文章
|
缓存
指令缓存队列
指令缓存队列
69 0
|
C++
c++ 队列
队列的数据结构
39 0
|
机器学习/深度学习 存储 C语言
队列的实现(上)
队列的实现(上)
队列的实现(下)
队列的实现(下)
|
C# C++ 索引
用C#构造一个队列Queue。要求此队列是循环队列,并进行入队、出队的测试。
用C#构造一个队列Queue。要求此队列是循环队列,并进行入队、出队的测试。
203 0
用C#构造一个队列Queue。要求此队列是循环队列,并进行入队、出队的测试。
|
存储
队列的使用
队列的使用
81 0
|
存储
队列?是你了解的这样吗?
队列?是你了解的这样吗?
107 0
队列?是你了解的这样吗?
|
索引
队列及双端队列
队列及双端队列
102 0