Java集合Queue——针对实习面试

ops/2024/11/14 12:04:57/

目录

  • Java集合Queue
    • Queue接口的特点是什么?
    • Queue和Deque的区别?
    • ArrayDeque和LinkedList的区别?
    • 什么是PriorityQueue?
    • 什么是BlockingQueue?

Java集合Queue

在这里插入图片描述

Queue接口的特点是什么?

Queue接口在Java中是一个特殊的集合,它具有以下特点:

  1. 先进先出(FIFO)原则
    Queue接口遵循FIFO(先进先出)的原则,这意味着元素被添加到队列的末尾,并从队列的前端移除。

  2. 元素访问
    Queue提供了对队列头部和尾部元素的访问。peek()方法允许查看队列头部的元素而不移除它,而element()方法也用于获取队头元素,但与peek()不同,如果队列为空,element()会抛出NoSuchElementException异常。

  3. 添加和移除元素
    Queue接口提供了add(E e)remove()方法来添加和移除元素,这些方法在队列满或空时会抛出异常。为了更安全地处理这些情况,Queue还提供了offer(E e)poll()方法,它们在无法添加或移除元素时返回falsenull,而不是抛出异常。

  4. 容量限制
    某些Queue实现(如ArrayDequeLinkedBlockingQueue)有容量限制,而其他实现(如LinkedList)则没有容量限制。

  5. 双端队列(Deque)
    Queue可以扩展为Deque接口,这允许元素从队列的两端进行插入和移除操作,使得Queue既可以作为队列使用,也可以作为栈使用。

  6. 线程安全性
    Queue接口本身不提供线程安全的保证,但Java提供了BlockingQueue接口,它是Queue的子接口,提供了线程安全的队列实现,适用于多线程环境。

  7. 泛型支持
    Queue接口支持泛型,这意味着你可以指定队列中元素的类型,从而在编译时期提供类型安全。

  8. 优先级队列
    Queue的一个子接口PriorityQueue提供了优先级队列的实现,元素根据其自然顺序或通过提供的Comparator进行排序。

  9. 非阻塞和阻塞操作
    对于非阻塞操作,Queue提供了poll()offer()方法;对于阻塞操作,BlockingQueue提供了take()put()方法,这些方法在无法进行操作时会阻塞调用线程。

了解Queue接口的这些特点对于在Java中正确使用队列至关重要,无论是在单线程还是多线程环境中。

Queue和Deque的区别?

QueueDeque都是Java集合框架中的接口,它们都可以用来存储元素,但它们之间存在一些关键的区别:

  1. 顺序不同

    • Queue接口是先进先出(FIFO)的数据结构,元素从队尾添加,从队头移除。
    • Deque接口是双端队列,支持从两端添加和移除元素,既可以实现FIFO(队列)的行为,也可以实现后进先出(LIFO,即栈)的行为。
  2. 方法不同

    • Queue提供了add, offer, remove, poll, element, peek等方法。
    • Deque除了包含Queue的所有方法外,还提供了addFirst, addLast, offerFirst, offerLast, pollFirst, pollLast, removeFirst, removeLast, getFirst, getLast, peekFirst, peekLast等方法,这些方法允许从两端进行操作。
  3. 行为不同

    • Queue的行为更受限,只能从队头移除元素,从队尾添加元素。
    • Deque的行为更灵活,可以作为队列、栈或两者的组合来使用。
  4. 实现类不同

    • Queue的常见实现类有LinkedList, PriorityQueue, ArrayDeque(也是Deque的实现)。
    • Deque的常见实现类有ArrayDequeLinkedList
  5. 性能考虑

    • 对于QueueLinkedList是一个常见的选择,因为它允许快速的插入和删

ArrayDeque和LinkedList的区别?

ArrayDequeLinkedList都是Java中的双端队列(Deque)实现,但它们在内部数据结构和性能特性上有所不同。以下是它们的主要区别:

  1. 内部数据结构

    • ArrayDeque是基于动态数组实现的,这意味着它使用一个可扩展的数组来存储元素。
    • LinkedList是基于双向链表实现的,每个元素都包含对前一个和后一个元素的引用。
  2. 随机访问性能

    • ArrayDeque支持快速的随机访问,因为它的元素存储在数组中,可以通过索引直接访问。
    • LinkedList不支持快速随机访问,因为它需要从头或尾开始遍历链表才能到达特定位置。
  3. 内存占用

    • ArrayDeque的内存占用通常比LinkedList少,因为它不需要为每个元素存储额外的前驱和后继指针。
    • LinkedList的每个节点都需要额外的空间来存储两个指针(指向前一个和后一个元素),这增加了内存开销。
  4. 扩容操作

    • ArrayDeque在需要时会进行扩容操作,这涉及到创建一个新的数组并复制旧数组中的元素,这是一个相对昂贵的操作,但通常比链表操作快。
    • LinkedList不需要扩容操作,因为它总是能够通过创建新的节点来动态地添加元素。
  5. 插入和删除性能

    • ArrayDeque在两端的插入和删除操作上通常比LinkedList快,因为它不需要像链表那样维护前后节点的链接。
    • LinkedList在两端的插入和删除操作上也很快,因为它只需要改变几个节点的指针,但随机位置的插入和删除操作会慢一些。
  6. 线程安全性

    • 两者都不是线程安全的,但可以通过Collections.synchronizedDeque方法来创建线程安全的ArrayDequeLinkedList
  7. 使用场景

    • ArrayDeque适合于需要快速随机访问元素的场景,以及作为栈或队列使用时,元素数量相对固定的情况。
    • LinkedList适合于需要在列表中间频繁插入和删除元素的场景,或者作为队列使用时,元素数量频繁变化的情况。
  8. 实现的接口

    • ArrayDeque实现了Deque接口和Queue接口。
    • LinkedList实现了List接口、Deque接口和Queue接口。
  9. 性能特性

    • ArrayDeque在并发环境下的性能通常优于LinkedList,因为它的扩容操作和随机访问操作更快。

在选择ArrayDequeLinkedList时,需要根据具体的应用场景和性能要求来决定使用哪一个。如果需要频繁的随机访问,或者队列的大小相对固定,ArrayDeque可能是更好的选择。如果需要在列表中间频繁地进行插入和删除操作,或者队列的大小频繁变化,LinkedList可能更合适。

什么是PriorityQueue?

PriorityQueue是Java中的一个类,它实现了Queue接口,并且是java.util包的一部分。以下是PriorityQueue的一些关键特性:

  1. 排序

    • PriorityQueue是一个优先级队列,其中元素根据它们的自然顺序或者通过提供的Comparator进行排序。队列的头部(队首)总是队列中具有最高优先级的元素。
  2. 无界队列

    • 默认情况下,PriorityQueue是一个无界队列,这意味着它可以无限增长,除非内存不足。
  3. 线程不安全

    • PriorityQueue不是线程安全的。如果需要线程安全的优先级队列,可以使用PriorityBlockingQueue
  4. 元素唯一性

    • PriorityQueue不允许插入null元素,并且根据使用的比较器(Comparator),可能也不支持元素重复。
  5. 插入和删除操作

    • PriorityQueue提供了offer(E e)方法来添加元素,和poll()方法来移除并返回队列头部的元素。这些操作的时间复杂度是O(log(n))
  6. 元素访问

    • 可以通过peek()方法来查看但不移除队列头部的元素,如果队列为空,则返回null
  7. 自定义排序

    • 在创建PriorityQueue实例时,可以提供一个Comparator来定义元素的排序规则。
  8. 迭代器

    • PriorityQueue提供了一个迭代器,允许按优先级顺序遍历队列中的元素。
  9. 堆的实现

    • PriorityQueue通常使用堆数据结构(通常是二叉堆)来存储元素,以保证高效的插入和删除操作。
  10. 使用场景

    • PriorityQueue适用于需要根据优先级处理元素的场景,例如任务调度、事件驱动模拟等。

下面是一个简单的PriorityQueue使用示例:

java">import java.util.PriorityQueue;public class PriorityQueueExample {public static void main(String[] args) {PriorityQueue<Integer> pq = new PriorityQueue<>(); // 默认自然顺序排序pq.offer(3);pq.offer(1);pq.offer(2);System.out.println(pq.poll()); // 输出 1System.out.println(pq.poll()); // 输出 2System.out.println(pq.poll()); // 输出 3}
}

在这个例子中,整数被添加到优先级队列中,并按照自然顺序(升序)排序。使用poll()方法可以按优先级顺序移除元素。

什么是BlockingQueue?

BlockingQueue是Java并发包java.util.concurrent中的一个接口,它继承自java.util.Queue接口。BlockingQueue提供了线程安全的队列实现,主要用于多线程之间的数据交换。以下是BlockingQueue的一些关键特性:

  1. 线程安全

    • BlockingQueue的所有实现都是线程安全的,这意味着它们可以被多个线程安全地访问而不需要额外的同步。
  2. 阻塞操作

    • BlockingQueue提供了阻塞的插入(put)和移除(take)操作。当队列满时,插入操作会阻塞,直到队列中有空间;当队列空时,移除操作会阻塞,直到队列中有元素。
  3. 可选的公平性

    • 一些BlockingQueue实现(如LinkedBlockingQueue)允许构造函数中指定公平性(fairness)。如果设置为公平性模式,线程将根据它们等待的时间来访问队列,而不公平的队列可能允许饥饿现象发生。
  4. 容量限制

    • 某些BlockingQueue实现(如ArrayBlockingQueueLinkedBlockingQueue)有固定容量,而其他实现(如LinkedBlockingQueue的无界版本)可以有无限容量。
  5. 非阻塞操作

    • 除了阻塞操作外,BlockingQueue还提供了非阻塞的插入(offer)和移除(poll)操作,这些操作在无法立即完成时会立即返回。
  6. 支持超时

    • BlockingQueue提供了带有超时的插入(offer(E e, long timeout, TimeUnit unit))和移除(poll(long timeout, TimeUnit unit))操作,允许线程在等待一定时间后放弃。
  7. 支持中断

    • BlockingQueue的阻塞操作可以通过中断来响应中断信号,允许线程在等待时响应中断,提高程序的响应性。
  8. 常见实现

    • ArrayBlockingQueue:一个由数组支持的有界阻塞队列。
    • LinkedBlockingQueue:一个由链表支持的可选有界阻塞队列。
    • PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
    • SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等待一个移除操作,反之亦然。
  9. 使用场景

    • BlockingQueue适用于生产者-消费者问题,其中生产者线程将元素放入队列,消费者线程从队列中取出元素。

下面是一个简单的BlockingQueue使用示例:

java">import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;public class BlockingQueueExample {public static void main(String[] args) throws InterruptedException {BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();// 生产者线程Thread producer = new Thread(() -> {try {queue.put(1); // 将元素放入队列System.out.println("Produced: 1");} catch (InterruptedException e) {Thread.currentThread().interrupt();}});// 消费者线程Thread consumer = new Thread(() -> {try {int element = queue.take(); // 从队列中取出元素System.out.println("Consumed: " + element);} catch (InterruptedException e) {Thread.currentThread().interrupt();}});producer.start();consumer.start();producer.join();consumer.join();}
}

在这个例子中,生产者线程将一个元素放入LinkedBlockingQueue,而消费者线程从队列中取出该元素。如果队列为空,take方法将阻塞消费者线程,直到队列中有元素可用。


http://www.ppmy.cn/ops/133233.html

相关文章

Java Review - 线程池原理源码解析

文章目录 Pre为什么要用线程池线程池的优点&#xff08;1&#xff09;重复利用线程&#xff08;2&#xff09;控制线程的数量 线程池实现原理线程池ThreadPoolExecutor类关系线程池的工作流程任务队列空闲线程的存活时间参数ThreadFactory拒绝策略被拒绝后的任务如何再次执行 向…

单调栈—acwing

一、题目&#xff1a; AcWing 830. 单调栈 - AcWing 暴力算法思想 双指针算法&#xff0c;本质上是比较操作&#xff0c;两个循环&#xff0c;时间复杂度高。通过栈可以一次遍历。 可以知道&#xff0c;只要前面有一个小于我的数&#xff0c;就可以。如果前面的数&#xff…

PDF24:多功能 PDF 工具使用指南

PDF24&#xff1a;多功能 PDF 工具使用指南 在日常工作和学习中&#xff0c;PDF 是一种常见且重要的文档格式。无论是查看、编辑、合并&#xff0c;还是转换 PDF 文件&#xff0c;能够快速高效地处理 PDF 文档对于提高工作效率至关重要。PDF24 是一款免费、功能全面的 PDF 工具…

OSPF动态路由配置实验:实现高效网络自动化

实验主题&#xff1a;OSPF动态路由协议配置 实验背景 OSPF&#xff08;Open Shortest Path First&#xff09;是一种基于链路状态的路由协议&#xff0c;广泛应用于中大型网络中。它采用Dijkstra算法计算最短路径&#xff0c;以确保网络中的路由更新快速、稳定&#xff0c;并能…

基于微信小程序实现个人健康管理系统

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

2024年三个月自学手册 网络安全(黑客技术)

&#x1f91f; 基于入门网络安全/黑客打造的&#xff1a;&#x1f449;黑客&网络安全入门&进阶学习资源包 前言 什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、…

鸿蒙NEXT开发案例:转盘

【1】引言&#xff08;完整代码在最后面&#xff09; 在鸿蒙NEXT系统中&#xff0c;开发一个有趣且实用的转盘应用不仅可以提升用户体验&#xff0c;还能展示鸿蒙系统的强大功能。本文将详细介绍如何使用鸿蒙NEXT系统开发一个转盘应用&#xff0c;涵盖从组件定义到用户交互的完…

100+SCI科研绘图系列教程(R和python)

科研绘图系列&#xff1a;箱线图加百分比点图展示组间差异-CSDN博客科研绘图系列&#xff1a;箱线图加蜜蜂图展示组间数据分布-CSDN博客科研绘图系列&#xff1a;小提琴图和双侧小提琴图展示组间差异-CSDN博客科研绘图系列&#xff1a;组间差异的STAMP图的ggplot2实现-CSDN博客…