主题
慧策(一面) 已完结
日期
2024 年 9 月 6 日
自我介绍
面试官您好,我是 wmh,是软件工程专业的 25 届应届生。
我的主要技术栈是 Spring Boot、MySQL、Redis。也会使用前端框架 Vue3,有一定的运维经验。
在校参与过学校项目组工作,有在校团队项目经验。参与过需求分析、数据库设计、开发、测试、部署等项目全流程。
在校期间完成了定时微服务、在线判题平台、个人导航站等项目,也与项目组成员合作开发过学校实验室预约系统、低代码平台组件库设计、学校申硕平台的二次开发等。
在校期间多次参与竞赛,曾获蓝桥杯省一和 CCPC 河北省赛的铜奖。
定时微服务
定到早上 8 点发布,你这个时间是怎么判断?怎么触发的?
任务创建使用了 Web 模块和迁移模块。
- web 模块:提供 api 接口用来提交、激活定时任务。
- 迁移模块:主要负责定期生成定时任务的工作,定时器创建后不会立即生成所以任务,这个任务是无限的,所以使用迁移模块定期生成最近 1 小时的任务。
任务的调度和触发使用到了 3 个模块和 2 个线程池。
- 调度模块:通过定时程序,每分钟将当前时间的所有分片放入线程池进行触发,每个线程对应一个分片。
- 触发模块:每秒进行一次轮循,将需要被执行的任务放入线程池进行执行,每个线程对应一个需要被执行任务。
- 执行模块:执行模块拿到任务,通过回调接口通知调用方,并记录日志。
迁移模块的定时是如何触发的?
使用 Spring 自带的定时任务 @Scheduled
,抢到 Redis 分布式锁的线程执行迁移逻辑。
为什么要把任务放到 zset 里?是有一个什么样的考量?
定时任务是有序的,通过时间顺序来触发任务,能够提高访问速度。
JUC
创建一个线程池有哪些参数?
核心线程数、最大线程数、存活时间、任务队列、拒绝策略
项目里定义线程池是哪种类型的任务队列?
使用了较大容量的有界阻塞队列,避免无界阻塞队列会出现内存泄漏问题。
核心线程数设了 20,最大线程数设了100。现在有一个新的任务被提交,它在里面那个流转的这个流程是什么?
- 任务提交到线程池
- 线程池检查当前活动线程数
- 小于 20:使用核心线程
- 大于 20:创建新线程,并执行
- 执行任务
- 执行完成后判断活动线程
- 小于 20:线程存活
- 大于 20:等待存活时间后且未被使用,会被销毁
了解过什么 Java 中的锁?
- synchronized:同步代码块
- ReentrantLock:可重入的互斥锁
- ReentrantReadWriteLock:读写锁,允许多个读线程同时访问,但写线程独占访问
- StampedLock:提供了乐观读锁,性能更高,但使用起来更复杂
synchronized 怎么保证会被锁上?
- 每个对象在内存中都存在一个与之关联的隐式监视器锁(Monitor)。
- 当一个线程进入
synchronized
方法或代码块时,它会尝试获取该对象的监视器锁。如果成功,则进入同步块执行代码;否则,线程将被阻塞,直到锁被释放。 - 线程在退出同步方法或代码块时会自动释放该监视器锁。
Redis
Redis 分布式锁执行的命令是什么
setnx
Redis 的持久化方式是什么?区别是什么?
RDB 是保存快照,AOF 是追加日志。
默认配置下,一分钟修改 10 个值,会被存到 RDB 吗?
不会,默认配置下一分钟至少 10000 次修改才会执行 RDB 备份。
save 900 1
save 300 10
save 60 10000
AOF 是逐条记录还是批量记录?
默认情况下 Redis 的 AOF 是逐条记录写操作。
ZSet 底层是什么数据结构?
跳表
跳表的结构和特点是什么?
跳表是链表的一种。相比普通链表,增加了多级索引,通过索引可以实现 的元素查找效率。
ZSet 取值的时间复杂度是多少?
平衡二叉树获取一个节点的时间复杂度是多少
Java 集合框架
HashMap 的数据结构是什么?
哈希表加链表或红黑树
HashMap 什么情况会扩容,扩容到多大?
存放数量大于容量 * 扩容因子(默认 0.75)时会触发扩容。
扩容到原来的 2 倍。
为什么扩容到 2 倍?
哈希表使用哈希值取模运算来确定元素存储的位置,当 HashMap 长度是 2 的幂次方时,取模操作能转化为位运算,提高操作效率。
HashMap 中链表过长会触发什么?
HashMap 容量达到 64 且链表长度大于 8 时会转换为红黑树
HashMap 中红黑树会变成链表吗?
当长度减少到 6 及以下时,红黑树会转换回链表。
ConcurrentHashMap 如何保证线程安全?
- 分段锁:早期版本整个哈希表被分成多个段,每个段有自己的锁。
- 节点锁:新版本每个桶有自己的锁。
- 对于链表,会在节点级别使用 synchronized 锁定
- 对于红黑树,会使用树锁。
- CAS 操作:在插入新元素时使用 CAS 操作来保证原子性
- Synchronized 和 ReentrantLock:在 rehash 时会使用内部锁来保证复杂操作的原子性
Java 基础
有一个接口的方法是被 final 修饰了,能在实现类里面还能去实现吗?
接口方法不能用 final 修饰

重载和重写的区别
- 重载是一个方法名通过不同的参数、返回值,有着不同的实现
- 重写是子类重写并覆盖父类的方法,要求方法名和参数一致
重写时可以修改可见范围吗?
子类重写可以放宽可见性,不能收紧可见性。
String 底层的结构是什么?
String 底层使用 final
修饰的字符数组( char[]
)或字节数组(byte[]
)
StringBuilder 和 StringBuffer 的区别
StringBuffer 线程安全,StringBuilder 线程不安全
StringBuffer 怎么保证线程安全?
StringBuffer 中的 insert()
和 append()
方法使用 synchronized 修饰。
JVM
字符串存放在 Java 内存结构的哪里?
字符串常量池在 jdk7 之前存放在方法区,jdk8 以后存放在堆中。为了方便垃圾回收。
JDK1.8中字符串常量池和运行时常量池逻辑上属于方法区,但是实际存放在堆内存中
JVM 内存结构都有什么?
堆、虚拟机栈、本地方法栈、方法区、程序计数器
堆区再细分的话还有哪些区域?
- 年轻代
- 老年代
- 永久代 / 元空间
新生代常见的垃圾回收算法
复制清除算法:将存活的对象从一个内存区域复制到另一个内存区域,释放掉不再使用的内存。
年轻代被划分为三个区域:伊甸园 Eden 区、幸存区 From Survivor 区和幸存区 To Survivor 区。
Java 的类加载的机制是什么
双亲委派机制
类加载器自上而下都是什么?
- 启动类加载器
- 扩展类加载器
- 应用程序类加载器
写了和 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 配置文件如何控制使用哪个
- 在 application 中配置:
spring.profiles.active=dev
- 运行时指定参数:
--spring.profiles.active=dev
多个配置文件的读取顺序是什么?
- bootstrap.yaml:最先加载,用于引导配置。
- application.yaml:作为默认配置文件加载。
- application-dev.yaml:在指定环境激活时加载,并覆盖
application.yaml
中的相同属性。 - Nacos 配置中心:从 Nacos 中加载的配置,覆盖本地配置中的相同属性。
拦截器和过滤器的区别?顺序是什么?
先触发过滤器,再触发拦截器
- 过滤器是 Tomcat 提供的
- 拦截器是 Spring 的组件
MySQL
InnoDB 和 MyISAM 的区别
- InnoDB 支持行级锁和事务,MyISAM 只有表锁,没有事务。
- InnoDB 将索引和数据存放在一起,B+ 树叶子结点存放数据;MyISAM 将索引和数据分开存储,B+ 树中存放数据地址。
索引都有哪些类型?
- 主键索引
- 唯一索引
- 普通索引
- 联合索引
- 前缀索引
索引的数据结构是什么?
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 的区别
- left join:左表所有数据以及其交集部分
- right join:右表所有数据以及其交集部分
- inner join:两表交集部分
Spring 如何使用事务?
使用 @Transactional
注解
❓Spring 事务什么时候会失效?事务传播行为是什么?
TBD...
事务的隔离级别有什么?
- 读已提交
- 读未提交
- 可重复读
- 串行化
MySQL 的事务问题都有哪些?
- 脏读:在一个事务读取了另一个事务未提交的数据
- 不可重复读:同一事务多次读取数据时得到不同的结果。
- 幻读:一个事务在第一次读取时的数据集与第二次读取时的数据集不一致
- 死锁:多个事务互相等待对方释放资源
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 位:
-
文件、d
目录、l
链接文件 - 2-4 位:指文件拥有者的权限
- 5-7 位:指文件拥有者所在用户组的权限
- 8-10 位:其他用户的权限
权限 | 缩写 | 数字符号 |
---|---|---|
读 | r | 4 |
写 | w | 2 |
执行 | x | 1 |
无权限 | - | 0 |
如何给文件加可执行权限?
sh
chmod +x script.sh
chmod 755 script.sh
数据结构
快排的时间复杂度是什么
,最差情况是
冒泡排序的时间复杂度是什么
,最好情况是