Java综合知识——JAVA中几种重要的队列、使用场景、实现方式与特点

1.1.2 JAVA中几种重要的队列、使用场景、实现方式与特点

一、什么是队列?

队列,实质是一种存储数据的结构,通常用链表或者数组实现。一般具备FIFO(先进先出)的特性,当然也有双端队列(Deque),优先队列等。主要的操作:入队(Enqueue)和出队(Dequeue).

img

在Java中, 定义了队列的基本操作,接口类型为 java.util.Queue,接口定义如下所示。Queue 定义了两套队列操作方法:

public interface Queue<E> extends Collection<E> {
    //插入元素,成功返回true,失败抛出异常
    boolean add(E e);
​
    //插入元素,成功返回true,失败返回false或抛出异常 
    boolean offer(E e);
​
    //取出并移除头部元素,空队列抛出异常 
    E remove();
​
    //取出并移除头部元素,空队列返回null 
    E poll();
​
    //取出但不移除头部元素,空队列抛出异常 
    E element();
​
    //取出但不移除头部元素,空队列返回null 
    E peek();
​
}

Queue 作为先进先出队列,只能从头部取元素、插入元素到尾部。

Java 同样定义了双向队列 Deque,可以同时在头部、尾部插入和取出元素,接口定义如下所示,针对头部操作方法为 xxxFirst、针对尾部操作方法为 xxxLast:

public interface Deque<E> extends Queue<E> {
    //插入元素到队列头部,失败抛出异常 
    void addFirst(E e);
​
    //插入元素到队列尾部,失败抛出异常  
    void addLast(E e);
​
    //插入元素到队列头部,失败返回false或抛出异常 
    boolean offerFirst(E e);
​
    //插入元素到队列尾部,失败返回false抛出异常  
    boolean offerLast(E e);
​
    //取出并移除头部元素,空队列抛出异常 
    E removeFirst();
​
    //取出并移除尾部元素,空队列抛出异常 
    E removeLast();
​
    //取出并移除头部元素,空队列返回null
    E pollFirst();
​
    //取出并移除尾部元素,空队列返回null
    E pollLast();
​
    //取出但不移除头部元素,空队列抛出异常
    E getFirst();
​
    //取出但不移除尾部元素,空队列抛出异常
    E getLast();
​
    //取出但不移除头部元素,空队列返回null
    E peekFirst();
​
    //取出但不移除尾部元素,空队列返回null
    E peekLast();
​
    //移除指定头部元素,若不存在队列不变,移除成功返回true 
    boolean removeFirstOccurrence(Object o);
​
    //移除指定尾部元素,若不存在队列不变,移除成功返回true 
    boolean removeLastOccurrence(Object o);
​
    //单向队列方法,参考Queue   
    //栈方法,参考栈
    //集合方法,参考集合定义   
}

不仅如此,Java 并发工具包中定义了阻塞队列 BlockingQueue 和 BlockingDueue。阻塞队列在前面的队列定义基础上增加了以下几个方法,来支持阻塞操作:

  • take:取出并移除元素,如队列为空则一直阻塞直到有元素;

  • put:插入元素,如队列满则一直阻塞直到有空位可以插入元素;

  • 可超时的offer:插入元素并指定超时时间,如队列满等待指定的时间;

  • 可超时的poll:取出并移除元素,如队列空等待指定的时间。

一般情况下 offer() 和 poll() 方法配合使用,put() 和 take() 阻塞方法配合使用,add() 和 remove() 方法会配合使用,程序中常用的是 offer() 和 poll() 方法,因此这两个方法比较友好,不会报错。

二、队列的分类

Java 中的这些队列可以从不同的维度进行分类,例如可以从阻塞和非阻塞进行分类,也可以从有界和无界进行分类,而本文将从队列的功能上进行分类,例如:优先队列、普通队列、双端队列、延迟队列等

file

1、阻塞队列与非阻塞队列
1.1 阻塞队列

阻塞队列(Blocking Queue)提供了可阻塞的 put 和 take 方法,它们与可定时的 offer 和 poll 是等价的。如果队列满了 put 方法会被阻塞等到有空间可用再将元素插入;如果队列是空的,那么 take 方法也会阻塞,直到有元素可用。当队列永远不会被充满时,put 方法和 take 方法就永远不会阻塞。在java包"java.util.concurrent"中,提供六个实现了"BlockingQueue"接口的阻塞队列:

  1. ArrayBlockingQueue 用数组实现的有界阻塞队列;

  2. LinkedBlockingQueue 基于链表实现的有界阻塞队列

  3. PriorityBlockingQueue是一个带优先级的队列,基于堆数据结构的;

  4. DelayQueue是在PriorityQueue基础上实现的,底层也是数组构造方法,是一个存放Delayed 元素的无界阻塞队列;

  5. SynchronousQueue 一个没有容量的队列 ,不会存储数据;

  6. LinkedBlockingDeque 是双向链表实现的双向并发阻塞队列;

1.2非阻塞队列

所有无Blocking Queue的都是非阻塞,并且它不会包含 put 和 take 方法。

2、有界队列和无界队列
2.1 有界队列

是指有固定大小的队列,比如设定了固定大小的 ArrayBlockingQueue,又或者大小为 0 的 SynchronousQueue。

2.2 无界队列

指的是没有设置固定大小的队列,但其实如果没有设置固定大小也是有默认值的,只不过默认值是 Integer.MAX_VALUE。

3、双端队列

Deque是一个双端队列接口,继承自Queue接口,Deque的实现类是LinkedList、ArrayDeque、LinkedBlockingDeque,其中LinkedList是最常用的。

Java双端队列-CSDN博客

4、优先队列

优先队列(PriorityQueue)是一种特殊的队列,它并不是先进先出的,而是优先级高的元素先出队。 优先队列是根据二叉堆实现的。最大堆和最小堆。

5、延迟队列

延迟队列(DelayQueue)是基于优先队列 PriorityQueue 实现的,它可以看作是一种以时间为度量单位的优先的队列,当入队的元素到达指定的延迟时间之后方可出队。

三、队列的使用场景

最典型的就是线程池,不同的线程池都是基于不同的队列来实现多任务等待的。

1.LinkedBlockingQueue使用场景:

在项目的一些核心业务且生产和消费速度相似的场景中:订单完成的邮件/短信提醒。 订单系统中当用户下单成功后,将信息放入ArrayBlockingQueue中,由消息推送系统取出数据进行消息推送提示用户下单成功。如果订单的成交量非常大,那么使用ArrayBlockingQueue就会有一些问题,固定数组很容易被使用完,此时调用的线程会进入阻塞,那么可能无法及时将消息推送出去,所以使用LinkedBlockingQueue比较合适,但是要注意消费速度不能太低,不然很容易内存被使用完。

2.PriorityBlockingQueue使用场景:

在项目上存在优先级的业务:VIP排队购票 用户购票的时候,根据用户不同的等级,优先放到队伍的前面,当存在票源的时候,根据优先级分配

3.DelayQueue使用场景 :

由于是基于优先级队列实现,但是它比较的是时间,我们可以根据需要去倒叙或者正序排列(一般都是倒叙,用于倒计时)。所以适用于:

订单超时取消功能、网站刷题倒计时 用户下订单未支付开始倒计时,超时则释放订单中的资源,如果取消或者完成支付,我们再将队列中的数据移除掉。

4.SynchronousQueue使用场景:

参考线程池newCachedThreadPool()。 如果我们不确定每一个来自生产者请求数量但是需要很快的处理掉,那么配合SynchronousQueue为每个生产者请求分配一个消费线程是最简洁的办法。

cking Queue)提供了可阻塞的 put 和 take 方法,它们与可定时的 offer 和 poll 是等价的。如果队列满了 put 方法会被阻塞等到有空间可用再将元素插入;如果队列是空的,那么 take 方法也会阻塞,直到有元素可用。当队列永远不会被充满时,put 方法和 take 方法就永远不会阻塞。在java包"java.util.concurrent"中,提供六个实现了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值