Skip to content

慧策(一面) 已完结

日期

2024 年 9 月 6 日

自我介绍

面试官您好,我是 wmh,是软件工程专业的 25 届应届生。

我的主要技术栈是 Spring Boot、MySQL、Redis。也会使用前端框架 Vue3,有一定的运维经验。

在校参与过学校项目组工作,有在校团队项目经验。参与过需求分析、数据库设计、开发、测试、部署等项目全流程。

在校期间完成了定时微服务、在线判题平台、个人导航站等项目,也与项目组成员合作开发过学校实验室预约系统、低代码平台组件库设计、学校申硕平台的二次开发等。

在校期间多次参与竞赛,曾获蓝桥杯省一和 CCPC 河北省赛的铜奖。

定时微服务

定到早上 8 点发布,你这个时间是怎么判断?怎么触发的?

任务创建使用了 Web 模块和迁移模块。

  1. web 模块:提供 api 接口用来提交、激活定时任务。
  2. 迁移模块:主要负责定期生成定时任务的工作,定时器创建后不会立即生成所以任务,这个任务是无限的,所以使用迁移模块定期生成最近 1 小时的任务。

任务的调度和触发使用到了 3 个模块和 2 个线程池。

  1. 调度模块:通过定时程序,每分钟将当前时间的所有分片放入线程池进行触发,每个线程对应一个分片。
  2. 触发模块:每秒进行一次轮循,将需要被执行的任务放入线程池进行执行,每个线程对应一个需要被执行任务。
  3. 执行模块:执行模块拿到任务,通过回调接口通知调用方,并记录日志。

迁移模块的定时是如何触发的?

使用 Spring 自带的定时任务 @Scheduled,抢到 Redis 分布式锁的线程执行迁移逻辑。

为什么要把任务放到 zset 里?是有一个什么样的考量?

定时任务是有序的,通过时间顺序来触发任务,能够提高访问速度。

JUC

创建一个线程池有哪些参数?

核心线程数、最大线程数、存活时间、任务队列、拒绝策略

项目里定义线程池是哪种类型的任务队列?

使用了较大容量的有界阻塞队列,避免无界阻塞队列会出现内存泄漏问题。

核心线程数设了 20,最大线程数设了100。现在有一个新的任务被提交,它在里面那个流转的这个流程是什么?

  1. 任务提交到线程池
  2. 线程池检查当前活动线程数
    1. 小于 20:使用核心线程
    2. 大于 20:创建新线程,并执行
  3. 执行任务
  4. 执行完成后判断活动线程
    1. 小于 20:线程存活
    2. 大于 20:等待存活时间后且未被使用,会被销毁

了解过什么 Java 中的锁?

  1. synchronized:同步代码块
  2. ReentrantLock:可重入的互斥锁
  3. ReentrantReadWriteLock:读写锁,允许多个读线程同时访问,但写线程独占访问
  4. StampedLock:提供了乐观读锁,性能更高,但使用起来更复杂

synchronized 怎么保证会被锁上?

  1. 每个对象在内存中都存在一个与之关联的隐式监视器锁(Monitor)。
  2. 当一个线程进入 synchronized 方法或代码块时,它会尝试获取该对象的监视器锁。如果成功,则进入同步块执行代码;否则,线程将被阻塞,直到锁被释放。
  3. 线程在退出同步方法或代码块时会自动释放该监视器锁。

Redis

Redis 分布式锁执行的命令是什么

setnx

Redis 的持久化方式是什么?区别是什么?

RDB 是保存快照,AOF 是追加日志。

默认配置下,一分钟修改 10 个值,会被存到 RDB 吗?

不会,默认配置下一分钟至少 10000 次修改才会执行 RDB 备份。

save 900 1
save 300 10
save 60 10000

AOF 是逐条记录还是批量记录?

默认情况下 Redis 的 AOF 是逐条记录写操作。

ZSet 底层是什么数据结构?

跳表

跳表的结构和特点是什么?

跳表是链表的一种。相比普通链表,增加了多级索引,通过索引可以实现 O(logn)O(\log n) 的元素查找效率。

ZSet 取值的时间复杂度是多少?

O(logn)O(\log n)

平衡二叉树获取一个节点的时间复杂度是多少

O(logn)O(\log n)

Java 集合框架

HashMap 的数据结构是什么?

哈希表加链表或红黑树

HashMap 什么情况会扩容,扩容到多大?

存放数量大于容量 * 扩容因子(默认 0.75)时会触发扩容。

扩容到原来的 2 倍。

为什么扩容到 2 倍?

哈希表使用哈希值取模运算来确定元素存储的位置,当 HashMap 长度是 2 的幂次方时,取模操作能转化为位运算,提高操作效率。

HashMap 中链表过长会触发什么?

HashMap 容量达到 64 且链表长度大于 8 时会转换为红黑树

HashMap 中红黑树会变成链表吗?

当长度减少到 6 及以下时,红黑树会转换回链表。

ConcurrentHashMap 如何保证线程安全?

  1. 分段锁:早期版本整个哈希表被分成多个段,每个段有自己的锁。
  2. 节点锁:新版本每个桶有自己的锁。
    1. 对于链表,会在节点级别使用 synchronized 锁定
    2. 对于红黑树,会使用树锁。
  3. CAS 操作:在插入新元素时使用 CAS 操作来保证原子性
  4. Synchronized 和 ReentrantLock:在 rehash 时会使用内部锁来保证复杂操作的原子性

Java 基础

有一个接口的方法是被 final 修饰了,能在实现类里面还能去实现吗?

接口方法不能用 final 修饰

重载和重写的区别

  1. 重载是一个方法名通过不同的参数、返回值,有着不同的实现
  2. 重写是子类重写并覆盖父类的方法,要求方法名和参数一致

重写时可以修改可见范围吗?

子类重写可以放宽可见性,不能收紧可见性。

String 底层的结构是什么?

String 底层使用 final 修饰的字符数组( char[])或字节数组(byte[]

StringBuilder 和 StringBuffer 的区别

StringBuffer 线程安全,StringBuilder 线程不安全

StringBuffer 怎么保证线程安全?

StringBuffer 中的 insert()append() 方法使用 synchronized 修饰。

JVM

字符串存放在 Java 内存结构的哪里?

字符串常量池在 jdk7 之前存放在方法区,jdk8 以后存放在堆中。为了方便垃圾回收。

JDK1.8中字符串常量池和运行时常量池逻辑上属于方法区,但是实际存放在堆内存中

JVM 内存结构都有什么?

堆、虚拟机栈、本地方法栈、方法区、程序计数器

堆区再细分的话还有哪些区域?

  1. 年轻代
  2. 老年代
  3. 永久代 / 元空间

新生代常见的垃圾回收算法

复制清除算法:将存活的对象从一个内存区域复制到另一个内存区域,释放掉不再使用的内存。

年轻代被划分为三个区域:伊甸园 Eden 区、幸存区 From Survivor 区和幸存区 To Survivor 区。

Java 的类加载的机制是什么

双亲委派机制

类加载器自上而下都是什么?

  1. 启动类加载器
  2. 扩展类加载器
  3. 应用程序类加载器

写了和 Spring 包名相同的类和方法,调用时会执行哪一个?

来自 gpt-4o

如果你的项目使用默认的类加载器配置,那么一般情况下,应用类加载器会优先加载引入的Spring包中的类,因为这些类一般都已经被系统预先加载。

你的自定义类将不会被加载。

项目的类使用什么加载器?Spring 的类呢?

都是应用类加载器

SSM 框架

解释一下什么是 IOC 和 DI

IOC 是控制翻转,核心是程序要依赖于接口,而不是具体实现类。

DI 是依赖注入,在需要其他对象时通过 Spring 传入。

DI 是 IOC 的一种实现方式。

DI 的底层原理是什么?

根据关系使用反射动态创建对象,并注入

Spring 的动态代理的两种类型是什么?区别是什么?

JDK 动态代理和 CGLIB 动态代理

  • JDK 动态代理通过实现接口
  • CGLIB 动态代理通过继承原始类

反射中去创建 Class 对象, .class 和 Class.forName() 的区别

Xxx.class 是静态获取并具有具体类型的 Class 对象

Class.forName("xxx") 是动态获取并具有通用类型的 Class 对象。

java
Class<Main> class1 = Main.class;
Class<?> class2 = Class.forName("Main");

你在什么功能上用使用过 AOP ?

记录日志、鉴权

Spring 是如何读取配置文件的?

Spring Boot 使用 @ConfigurationProperties 和相关的注解来读取配置类中的属性。当在配置文件中定义了属性,Spring Boot 会在启动过程中解析这些配置,并将它们绑定到相应的配置类中。

Spring Boot 会在启动时加载所有的自动配置类,这些类会根据你的配置文件中的内容来进行相应的设置。

多个 application-xxx 配置文件如何控制使用哪个

  1. 在 application 中配置: spring.profiles.active=dev
  2. 运行时指定参数: --spring.profiles.active=dev

多个配置文件的读取顺序是什么?

  1. bootstrap.yaml:最先加载,用于引导配置。
  2. application.yaml:作为默认配置文件加载。
  3. application-dev.yaml:在指定环境激活时加载,并覆盖 application.yaml 中的相同属性。
  4. Nacos 配置中心:从 Nacos 中加载的配置,覆盖本地配置中的相同属性。

拦截器和过滤器的区别?顺序是什么?

先触发过滤器,再触发拦截器

  1. 过滤器是 Tomcat 提供的
  2. 拦截器是 Spring 的组件

MySQL

InnoDB 和 MyISAM 的区别

  1. InnoDB 支持行级锁和事务,MyISAM 只有表锁,没有事务。
  2. InnoDB 将索引和数据存放在一起,B+ 树叶子结点存放数据;MyISAM 将索引和数据分开存储,B+ 树中存放数据地址。

索引都有哪些类型?

  1. 主键索引
  2. 唯一索引
  3. 普通索引
  4. 联合索引
  5. 前缀索引

索引的数据结构是什么?

B+ 树

B+ 树相比二叉树的优点是什么?

B+ 树是多叉树,树结构扁平;二叉树层级更高,需要频繁进行平衡。

聚簇索引和非聚簇索引的区别

聚簇索引通常是主键索引,叶子节点存放数据。

非聚簇索引通常是非主键的索引,叶子结点存放主键,需要回表查询。

联合索引 A、B,只查 B 会使用索引吗?

不能,联合索引需要满足最左匹配原则

where 条件先写 B 后写 A 会走索引吗?为什么?

会使用索引。

数据库优化器会识别索引的使用,不会因 where 子句中条件的顺序不同而影响索引的利用。

count(1)、count(*)、count(字段) 的区别

count(*) 会被优化器优化成 count(0),和 count(1) 性能相同,统计行数。

count(字段) 会统计字段非 NULL 的行数。

left join、right join、inner join 的区别

  1. left join:左表所有数据以及其交集部分
  2. right join:右表所有数据以及其交集部分
  3. inner join:两表交集部分

Spring 如何使用事务?

使用 @Transactional 注解

❓Spring 事务什么时候会失效?事务传播行为是什么?

TBD...

事务的隔离级别有什么?

  1. 读已提交
  2. 读未提交
  3. 可重复读
  4. 串行化

MySQL 的事务问题都有哪些?

  1. 脏读:在一个事务读取了另一个事务未提交的数据
  2. 不可重复读:同一事务多次读取数据时得到不同的结果。
  3. 幻读:一个事务在第一次读取时的数据集与第二次读取时的数据集不一致
  4. 死锁:多个事务互相等待对方释放资源

Linux

看日志(文本文件)可以使用哪些命令

cat、less、vim

cat 和 less 的区别

cat 用于将文件内容输出到标准输出,适合短文本

less 可以逐页查看文件内容,适合长文本

less 打开文件是默认定位在第 0 行,还是最后一行?

默认情况下,它会定位在文件的 第0行(即文件的开头)

less 打开文件如何直接跳转到最后一行?

文件打开,按下 G 键(注意是大写的 G),你会直接跳转到文件的最后一行。

  • g(小写)可以跳转到文件的第一行。
  • 使用方向键(上下箭头)或 j/k 键可以逐行移动。
  • / 然后输入搜索词可以在文件中进行搜索。

如何能够持续查看新追加的内容,比如滚动的日志?

使用 tail -f xxx.log 命令,tail 会持续输出新追加的内容

如何修改文件权限

chmod 命令

用户权限格式是什么?

-rw-r--r--@   1 wangminghao  staff    407665  8 10 14:35 wmh.pdf
  1. 第 1 位:- 文件、d 目录、l 链接文件
  2. 2-4 位:指文件拥有者的权限
  3. 5-7 位:指文件拥有者所在用户组的权限
  4. 8-10 位:其他用户的权限
权限缩写数字符号
r4
w2
执行x1
无权限-0

如何给文件加可执行权限?

sh
chmod +x script.sh

chmod 755 script.sh

数据结构

快排的时间复杂度是什么

O(logn)O(\log n),最差情况是 O(n2)O(n^2)

冒泡排序的时间复杂度是什么

O(n2)O(n^2),最好情况是 O(n)O(n)

Released under the MIT License.