面试系列-携程暑期实习一面

Java 基础

1、Java 中有哪些常见的数据结构?

图片来源于:JavaGuide

Java集合框架图
Java集合框架图

Java 中常见的数据结构包含了 List、Set、Map、Queue,在回答的时候,只要把经常使用的数据结构给说出来即可,不需要全部记住

如下:

List 列表: 有 ArrayList、LinkedList

1、ArrayList 是动态数组

2、LinkedList 是双向链表

Set 集合: 有 HashSet、LinkedHashSet、TreeSet

1、HashSet 基于 HashMap 实现,不保证元素的顺序,利用 Map 的 key 不能重复保证元素的唯一性

2、LinkedHashSet 继承自 HashSet,基于 LinkedHashMap 实现,通过链表维护元素的插入顺序

3、TreeSet 基于红黑树实现,元素自然排序或指定排序器排序

Map 哈希映射: 有 HashMap、LinkedHashMap、TreeMap、ConcurrentHashMap

1、HashMap 基于数组+链表+红黑树实现

2、LinkedHashMap 继承自 HashMap,通过链表维护元素插入顺序

3、TreeMap 基于红黑树实现,会对元素的 key 进行自然排序或指定排序器排序

4、ConcurrentHashMap 并发安全的 HashMap,在 JDK1.8 及以后通过 CAS + synchronized 实现线程安全

Queue 队列: 有 PriorityQueue、ArrayDeque

1、PriorityQueue 基于优先级堆的优先队列实现,元素自然排序或指定排序器排序

2、ArrayDeque 基于数组的双端队列

2、HashMap 介绍一下,key 可以设置为 null 吗?

HashMap 是哈希结构,存储 k-v 键值对,底层实现的话由数组+链表+红黑树进行实现

HashMap 中是可以存储 null 的 key 或 value 的,在 HashMap 中,为 null 的 key 只有一个,当传入 key 为 null 的时候,就会返回数组中索引为 0 的位置

3、ConcurrentHashMap 的 key 可以为 null 吗?

在 ConcurrentHashMap 中的 key 和 value 是不可以为 null 的

大家可以思考一下,为什么 HashMap 中 key 可以为 null,ConcurrentHashMap 中不可以呢?

ConcurrentHashMap 是并发安全的,因此是在多线程环境中使用的,如果 key 或者 value 可以为 null 的话,那么就会存在 二义性

因为一个线程在操作 ConcurrentHashMap 的时候,其他线程也有可能同时来进行修改,因此会存在 二义性 的问题:

如果 key 为 null,就无法区分这个 key 是否存在于 ConcurrentHashMap 中;如果 value 为 null,就无法区分这个 value 是不存在 ConcurrentHashMap 中还是该 value 被置为了 null

HashMap 中的 key 和 value 为什么可以为 null?

而 HashMap 中的 key 和 value 可以为 null 就是因为 HashMap 是并发不安全的,因此使用 HashMap 的话,都是在单线程环境下使用,一个线程操作的时候,其他的线程不会同时操作,因此不会存在二义性问题

那么为什么 ConcurrentHashMap 源码不设计成可以判断是否存在 null 值的 key?

如果 key 为 null,那么就会带来很多不必要的麻烦和开销。比如,你需要用额外的数据结构或者标志位来记录哪些 key 是 null 的,而且在多线程环境下,还要保证对这些额外的数据结构或者标志位的操作也是线程安全的。而且,key 为 null 的意义也不大,因为它并不能表示任何有用的信息。

4、如果多线程同时操作一个数据,会有什么问题,怎么解决?

会存在线程安全的问题,只需要控制多个线程之间的操作同步,并且对该变量添加 volatile 关键字,保证该变量对多个线程的可见性即可

控制多个线程之间操作同步的话,通过 synchronized 或者 ReentrantLock 进行控制即可

5、线程池介绍一下,线程池的参数中最大线程数可以设得比核心线程数小吗?

介绍线程池的时候,说一下线程池的几个核心参数,以及线程池的工作流程

线程池中重要的参数如下:

  • corePoolSize :核心线程数量
  • maximumPoolSize :线程池最大线程数量 = 核心线程数+非核心线程数
  • keepAliveTime :非核心线程存活时间
  • unit:空闲线程存活时间单位(keepAliveTime单位)
  • workQueue :工作队列(任务队列),存放等待执行的任务
    • LinkedBlockingQueue:无界的阻塞队列,最大长度为 Integer.MAX_VALUE
    • ArrayBlockingQueue:基于数组的有界阻塞队列,按FIFO排序
    • SynchronousQueue:同步队列,不存储元素,对于提交的任务,如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
    • PriorityBlockingQueue:具有优先级的无界阻塞队列,优先级通过参数Comparator实现。
  • threadFactory :线程工厂,创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等。
  • handler: 拒绝策略 ,有4种
    • AbortPolicy :直接抛出异常,默认策略
    • CallerRunsPolicy:用调用者所在的线程来执行任务
    • DiscardOldestPolicy:丢弃阻塞队列里最老的任务,也就是队列里靠前的任务
    • DiscardPolicy :当前任务直接丢弃

新加入一个任务,线程池处理流程如下:

  1. 如果核心线程数量未达到,创建核心线程执行
  2. 如果当前运行线程数量已经达到核心线程数量,查看任务队列是否已满
  3. 如果任务队列未满,将任务放到任务队列
  4. 如果任务队列已满,看最大线程数是否达到,如果未达到,就新建非核心线程处理
  5. 如果当前运行线程数量未达到最大线程数,则创建非核心线程执行
  6. 如果当前运行线程数量达到最大线程数,根据拒绝策略处理
image-20240227123406636
image-20240227123406636

线程池的参数中最大线程数可以设得比核心线程数小吗?

这个一般对于线程池有了解的都不会这么设置,最大线程数 = 核心线程数 +非核心线程数,所以最大线程数不可能比核心线程数还要小,这是错误的使用方式

JVM

6、JVM 内存结构

JVM 的内存结构分为:堆、虚拟机栈、本地方法栈、方法区

主要存储 JVM 中创建的对象,堆是多个线程共享的空间

方法区 主要存储编译后的 Java 代码,也就是 class 文件的信息

虚拟机栈 包括了一个个的栈帧,每执行一个方法,都会为该方法生成一个栈帧压入虚拟机栈中,当执行完该方法之后,就会将该栈帧弹出虚拟机栈,这个虚拟机栈是 线程私有 的,方法中的一些局部变量也会在该栈帧中进行存储

本地方法栈 类似于虚拟机栈,里边的栈帧就是使用到的本地方法,本地方法指的是底层的非 Java 代码,因为 Java是一门高级语言,我们不直接与操作系统资源、系统硬件打交道。如果想要直接与操作系统与硬件打交道,就需要使用到本地方法了

程序计数器 用于存储当前线程所执行的字节码指令的行号,让线程知道下一次要执行哪一个字节码指令,程序计数器是线程私有的

JVM 整体结构图如下:

JVM 架构
JVM 架构

7、垃圾回收算法和垃圾回收器都讲一下

垃圾回收算法有:标记-清除算法、复制算法、标记-压缩算法、分代回收算法

标记-清除算法 会从 GC Roots 开始遍历,将可到达的对象做标记,标记为存活对象,那么其他未标记的对象就是需要对象,将垃圾对象清除掉即可

缺点就是会产生内存碎片

复制算法 需要将内存区域分成大小相等的两块,当需要 GC 时,将其中一块内存区域中的存活对象复制到另外一块区域,再将原来的一块内存区域清空即可

优点是不会产生内存碎片,缺点是存在比较大的空间浪费

标记-压缩算法 是基于标记-清除算法的改进,先标记存活对象,之后将所有存活对象压缩到内存的一端,清除边界以外的垃圾对象即可

优点是既解决了标记-清除算法出现内存碎片的问题,又解决了复制算法中空间浪费的问题,但是效率低于复制算法

分代收集算法 是将 Java 堆分为新生代和老年代,这样就可以对不同生命周期的对象采取不同的收集方式,因为新生代中的对象生命周期短,存活率低,适合使用 复制算法 ,老年代生命周期长,存活率高,适合使用 标记-清除标记-压缩 算法

垃圾收集器

有 8 种垃圾回收器,分别用于不同分代的垃圾回收:

  • 新生代回收器:Serial、ParNew、Parallel Scavenge
  • 老年代回收器:Serial Old、Parallel Old、CMS
  • 整堆回收器:G1、ZGC

这里就不重复介绍了,可以参考 :JVM垃圾收集器

JDK1.8 中默认的垃圾收集器是 Parallel Scavenge(新生代)+Parallel Old(老年代)

公司中一般使用指定 G1 作为垃圾收集器的比较多 ,因为 G1 的特点就是天生适合用于大内存机器,无论内存多大,都可以指定期望的 GC 停顿时间,这样不至于停顿时间太长,导致用户体验卡顿

8、有看过 GC 日志吗

GC 日志的话可以通过 gceasy 工具进行分析,首先需要设置 VM Options 来开启 GC 日志打印:

 # 开启 GC 日志创建更详细的 GC 日志
 -XX:+PrintGCDetails 
 # 开启 GC 时间提示
-XX:+PrintGCTimeStamps,-XX:+PrintGCDateStamps
# 打印堆的GC日志
-XX:+PrintHeapAtGC 
# 指定GC日志路径
-Xloggc:./logs/gc.log

分析 GC 日志的话,就是将生成的 gc.log 日志文件放入 gceasy 工具进行分析,分析的话主要看以下这几个重要的参数:

1、新生代、老年代、元空间占用情况: 看一下分配的空间大小以及峰值空间大小,来判断是否空间分配不合理,在 JDK1.8 中,如果不指定元空间大小,默认的初始值为 21MB,最大值为系统内存大小,元空间太小会导致频繁 Full GC 来提升元空间大小,因此这一点要注意

2、平均/最大 GC 暂停时间: 看一下暂停时间有没有特别长,如果特别长,说明是存在问题的

3、GC 持续时间/GC 次数: 判断 GC 持续时间是否过长、GC 次数是否频繁,如果 Full GC 较为频繁,也是存在问题的(因为 Full GC 比较慢,要减少 Full GC 次数),之后就要分析 Full GC 原因,看看是有大对象、还是产生非常多的对象、还是元空间初始值太小了

详细 GC 日志分析可参考:通过 gceasy工具对生成的 GC 日志进行分析

MQ

9、项目中的 RocketMQ 怎么保证消息一定发出去且收到了?

这里问的就是 RocketMQ 如何保证消息的可靠性,避免消息在传输过程中丢失了

RocketMQ 作为分布式消息中间件,肯定是要尽可能保证消息传输的 可靠性 ,要保证消息的可靠性,先来思考一下从哪些方面保证呢?

这要看消息的生命周期,既然保证可靠性,那么就是要保证 A 发送给 B 的消息一定可以成功,那么首先要保证发送成功,其次要保证 B 接收成功,而在 RocketMQ 中,消息是先发送到 Broker 中了,那么还需要保证 MQ 在 Broker 中不会丢失

因此 RocketMQ 是从三方面保障了消息的可靠性:

  • 保证 生产者发送消息 的可靠性
  • 保证 Broker 存储消息 的可靠性
  • 保证 消费者消费消息 的可靠性
发送消息的可靠性

RocketMQ 在发送端保证发送消息的可靠性主要就是通过 重试机制 来实现的

生产者发送消息分为了 同步发送异步发送单向发送 三种方式:

  • 同步发送 :发送消息后,阻塞线程等待消息发送结果
  • 异步发送 :发送消息后,并不会阻塞等待,回调任务会在另一个线程中执行
  • 单向发送 :发送消息后,立即返回,不返回消息发送是否成功,因此不可以保证发送消息的可靠性

只有单向发送没有消息可靠性的保证,在 同步异步 发送中,都可以通过设置发送消息的 重试次数 来保证发送端的可靠性,默认重试次数为 2 次

并且还可以设置如果发送失败,尝试发送到其他 Broker 节点

// 同步设置重试次数
producer.setRetryTimesWhenSendFailed(3)
// 异步设置重试次数
producer.setRetryTimesWhenSendAsyncFailed(3);
// 如果发送失败,是否尝试发送到其他 Broker 节点
producer.setRetryAnotherBrokerWhenNotStoreOK(true);
存储消息的可靠性

可靠性保证一:消息落盘存储保证消息的可靠性

在消息发送到 Broker 之后,Broker 会将消息存储在磁盘中,这样如果 Broker 异常宕机之后,可以读取磁盘中的数据来保证消息的 可靠性

RocketMQ 如何存储消息:

RocketMQ 会先将消息写入到操作系统的 page cache 中,之后消息刷入磁盘分为了 同步刷盘异步刷盘 两种方式, 默认是异步刷盘方式

page cache 就是将文件映射到内存中,这样直接操作内存比较快,避免了频繁的磁盘 IO

Broker 通过 page cache异步刷盘 在保证消息可靠性的前提下,还尽可能提升了消息写入的性能

在 Broker 端写入消息的流程如下:

image-20240325151146744
image-20240325151146744

可以看到,这里写消息先写在了 JVM 的 堆外内存 中,而不是直接写在了 page cache 中,这是 RocketMQ 提供的 transientStorePoolEnabled(瞬时存储池启用)机制 来实现内存级别的读写分离(需要开启 transientStorePoolEnabled(瞬时存储池启用)机制 才会先写入 JVM 的堆外内存)

为什么要将消息先写在 堆外内存 呢?如果高并发的读写请求都直接落在 page cache 中的话,那么会导致对 page cache 的竞争太过于激烈,因此令写请求操作 堆外内存 ,读请求操作 page cache ,实现 读写分离 ,避免高并发情况下对 page cache 的激烈竞争

可靠性保证二:主从复制保证 Broker 的消息可靠性

上边是通过将消息写入磁盘来保证 Broker 存储端的消息可靠性,还有另一种方式:对 Broker 采用一主多从的方式部署,通过 主从复制 来保证消息的可靠性

在 Broker 主从复制时,会将 master 节点的消息同步到 slave 节点,slave 节点作为 master 节点的 热备份 存在,保证消息的可靠性

消费消息的可靠性

消费者为了保证消息的可靠性: 会先消费消息,再提交消息消费成功的状态 ,不过可能会出现 重复消费 的情况,因此需要业务方保证 幂等性 来解决重复消费的问题(可以建立一张消息消费表来避免重复消费)

可靠性保证一:消息重试保证可靠性

消费者只有返回 CONSUME_SUCCESS 才算消费完成,如果返回 CONSUME_LATER 则会按照不同的延迟时间再次消费,如果消费满 16 次之后还是未能消费成功,则会将消息发送到死信队列

可靠性保证二:死信队列保证可靠性

如果消息最终重试消费失败,并不会立即丢弃,而是将消息放入到了死信队列,之后还可以通过 MQ 提供的接口获取对应的消息, 保证消费消息的可靠性

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/432145.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Fyne ( go跨平台GUI )中文文档- 扩展Fyne (七)

本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法 go代码展示为Go 1.16 及更高版本, ide为goland2021.2 这是一个系列文章: Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客 Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客 Fyne ( go跨平台GUI…

OJ在线评测系统 后端基础部分开发 完善CRUD相关接口

完善相关接口 判斷编程语言是否合法 先从用户的请求拿到Language package com.dduo.dduoj.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.dduo.dduoj…

11-pg内核之锁管理器(六)死锁检测

概念 每个事务都在等待集合中的另一事务,由于这个集合是一个有限集合,因此一旦在这个等待的链条上产生了环,就会产生死锁。自旋锁和轻量锁属于系统锁,他们目前没有死锁检测机制,只能靠内核开发人员在开发过程中谨慎的…

JavaEE: 深入探索TCP网络编程的奇妙世界(二)

文章目录 TCP核心机制TCP核心机制二: 超时重传为啥会丢包?TCP如何对抗丢包?超时重传的时间设定超时时间该如何确定? TCP核心机制 前一篇文章 JavaEE: 深入探索TCP网络编程的奇妙世界(一) 书接上文~ TCP核心机制二: 超时重传 在网络传输中,并不会一帆风顺,而是可能出现&qu…

基础环境搭建以及大模型部署

文章目录 算力云基础环境搭建以及大模型部署创建实例(租用算力云)选择服务器(一台RTX 3090)选择镜像版本连接实例确认环境和显卡信息 安装大模型1.选择大模型2. 下载并安装大模型设置资源下载加速安装git-lfs下载大模型安装依赖的…

如何使用ssm实现基于SpringMVC网上选课系统的设计与实现

TOC ssm696基于SpringMVC网上选课系统的设计与实现jsp 研究背景和来源 目前的管理类系统已各种各样,涉及到生活中的每一个部分。购物类、网站类、信息统计类、办公类、官网类等非常丰富。我国各类系统的发展已非常成熟,这些系统依靠网络和计算机技术不…

如何使用ssm实现线上旅游体验系统+vue

TOC ssm691线上旅游体验系统vue 绪论 课题背景 身处网络时代,随着网络系统体系发展的不断成熟和完善,人们的生活也随之发生了很大的变化。目前,人们在追求较高物质生活的同时,也在想着如何使自身的精神内涵得到提升&#xff0…

15 Midjourney从零到商用·实战篇:建筑设计与室内设计

以前设计师生成一张效果图需要先画草稿,导入三维软件搭建场景后,再用渲染器渲染,而现在只需要有客户的意向图或者自己想法,在MidJourney中就能一键生成惊艳的效果图。 “给我一个prompt我能撬动整个设计界”。设计师在AI绘画面前似…

LLMs之RAG:MemoRAG(利用其记忆模型来实现对整个数据库的全局理解)的简介、安装和使用方法、案例应用之详细攻略

LLMs之RAG:MemoRAG(利用其记忆模型来实现对整个数据库的全局理解)的简介、安装和使用方法、案例应用之详细攻略 目录 MemoRAG的简介 0、更新日志 1、特性 2、路线图 MemoRAG的安装和使用方法 1、安装 安装依赖项 T1、从源码安装 T2、通过pip安装 2、使用方…

【简单介绍】DevOps是什么?

由于 DevOps 方法的广泛采用以及由此产生的快速产品交付和部署,许多部门已采用更敏捷的方法来开发生命周期。在满足市场速度和规模要求的同时,设计安全的软件一直是现代 IT 公司共同面临的问题。结果,超过 52% 的组织因为担心上市速度落后而放…

大数据毕业设计选题推荐-手机销售数据分析系统-Hive-Hadoop-Spark

✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…

Dubbo入门案例

Dubbo 学习地址:Dubbo3 简介_w3cschool; 01-Dubbo入门案例 ​ 我们先来新建一个Dubbo的小案例来体验一下Dubbo的使用,我们先来创建一个springboot的项目。 1.1-zookeeper下载启动 ​ 在编写我们的入门案例之前,我们需要先去下…

浅拷贝和深拷贝(Java 与 JavaScript)

一、Java 浅拷贝和深拷贝 在Java中,浅拷贝和深拷贝的主要区别在于对对象的引用和内容的复制方式。 浅拷贝 Java 的类型有基本数据类型和引用类型,基本数据类型是可以由 CPU 直接操作的类型,无论是深拷贝还是浅拷贝,都是会复制出…

C++ 二叉树

1. 二叉搜索树 1.1 二叉搜索树概念 二叉搜索树又称二叉排序树,他或者是一棵空树,或者是具有以下性质的二叉树: ①若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 ②若它的右子树不为空,则右子树上所有节…

PCL 用八叉树完成空间变化检测

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1八叉树构建与变化检测 2.1.2检测变化的点云 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接: PCL点云算法与项目实战案例汇总(长期更…

如何在O2OA中使用ElementUI组件进行审批流程工作表单设计

本文主要介绍如何在O2OA中进行审批流程表单或者工作流表单设计,O2OA主要采用拖拽可视化开发的方式完成流程表单的设计和配置,不需要过多的代码编写,业务人员可以直接进行修改操作。 在流程表单设计界面,可以在左边的工具栏找到Ele…

《线性代数》学渣笔记

文章目录 1 行列式1.1 克拉默法则1.2 基本性质1.3 余子式 M i j M_{ij} Mij​1.4 代数余子式 A i j ( − 1 ) i j ⋅ M i j A_{ij} (-1)^{ij} \cdot M_{ij} Aij​(−1)ij⋅Mij​1.5 具体型行列式计算(化为基本型)1.5.1 主对角线行列式:主…

Vue3 + ElementPlus 的后台菜单指引

文章目录 需求实现思路 需求 实现思路 引导页用 Drive.js 基本的使用操作这里写了一些菜单使用 ElementPlus 的组件,可以调用组件中暴露的这个方法,具体使用方法在这里说明 二者结合一下,就可以有这样的效果了

2024网安周 | 百度安全深度参与,探索人工智能与数字安全的融合发展之路

9月9日-15日,2024年国家网络安全宣传周在全国范围内统一举行,本届网安周继续以“网络安全为人民,网络安全靠人民”为主题,由中央宣传部、中央网信办、教育部、工业和信息化部、公安部、中国人民银行、国家广播电视总局、全国总工会…

K8s flink-operator 例子

1.参考官网: https://nightlies.apache.org/flink/flink-kubernetes-operator-docs-stable/docs/try-flink-kubernetes-operator/quick-start/ 2.首先环境具备 k8s、helm 我的环境 k8s 1.30 最新版本了 [rootk8s-master ~]# kubectl get no -owide NAME …