面试题(1)
🔹 Java 基础
1. HashMap 的底层结构?JDK 1.8 有什么变化?
答案:
JDK 1.7:数组 + 链表,链表头插法
JDK 1.8:
数组 + 链表/红黑树(链表长度 > 8 且数组长度 ≥ 64 时转为红黑树)
链表尾插法(解决多线程下可能的循环链表问题)
扩容时重新计算hash的方式优化(高位参与运算)
新增方法:
getOrDefault
、computeIfAbsent
等
2. synchronized 和 ReentrantLock 的区别?
答案:
特性 | synchronized | ReentrantLock |
---|---|---|
实现层面 | JVM层面 | JDK层面 |
锁的获取 | 自动获取释放 | 手动lock/unlock |
响应中断 | 不支持 | 支持lockInterruptibly() |
公平锁 | 非公平 | 可选择公平/非公平 |
条件变量 | 一个Condition | 多个Condition |
性能 | 优化后差距不大 | 高竞争下有优势 |
3. 什么是 volatile 关键字?它能保证原子性吗?
答案:
作用:
保证可见性:一个线程修改后,其他线程立即可见
禁止指令重排序
不能保证原子性:如
count++
这种复合操作不是原子的使用场景:状态标志位、DCL单例模式
4. 谈谈你对 JVM 内存模型的理解?
答案:
线程私有:
程序计数器:当前线程执行的字节码行号
虚拟机栈:方法执行的内存模型
本地方法栈:Native方法服务
线程共享:
堆:对象实例分配区域
方法区:类信息、常量、静态变量
JDK 1.8:元空间替代永久代
5. 什么是双亲委派模型?为什么要使用它?
答案:
工作机制:类加载请求先委派给父加载器,只有父加载器无法完成时才自己加载
层次结构:
Bootstrap ClassLoader
Extension ClassLoader
Application ClassLoader
自定义ClassLoader
优点:
避免类的重复加载
保证核心类库安全(如java.lang.Object)
🔹 Spring & Spring Boot
1. Spring Boot 自动装配的原理是什么?
答案:
核心注解:
@SpringBootApplication
→@EnableAutoConfiguration
关键文件:
META-INF/spring.factories
流程:
扫描
spring.factories
中的EnableAutoConfiguration
配置通过
@Conditional
条件判断决定是否装配创建并注册Bean到IOC容器
2. Spring 中 Bean 的生命周期?
答案:
实例化Bean
属性赋值(依赖注入)
调用Aware接口方法(BeanNameAware、BeanFactoryAware)
BeanPostProcessor前置处理
初始化方法(@PostConstruct、InitializingBean)
BeanPostProcessor后置处理
Bean就绪使用
容器关闭时调用销毁方法(@PreDestroy、DisposableBean)
3. Spring 事务传播机制有哪些?如何使用?
答案:
REQUIRED(默认):有事务加入,无事务新建
REQUIRES_NEW:新建事务,挂起当前事务
NESTED:嵌套事务,外部事务回滚会影响内部
SUPPORTS:有事务就用,没有就算了
NOT_SUPPORTED:非事务执行,挂起当前事务
MANDATORY:必须有事务,否则抛异常
NEVER:必须无事务,否则抛异常
4. Spring MVC 的工作流程是怎样的?
答案:
用户请求 → DispatcherServlet
DispatcherServlet 查询 HandlerMapping
调用 HandlerAdapter 执行 Controller
Controller 返回 ModelAndView
视图解析器解析视图
渲染视图并返回响应
5. 如何自定义一个 Starter?
答案:
// 1. 创建配置类
@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic MyService myService() {return new MyService();}
}
// 2. 在META-INF/spring.factories中配置
// org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.MyAutoConfiguration
🔹 数据库 & Redis
1. MySQL 索引底层结构?什么是聚簇索引?
答案:
底层结构:B+Tree
聚簇索引:
索引与数据存储在一起
InnoDB主键就是聚簇索引
一个表只有一个聚簇索引
非聚簇索引:
索引与数据分离
叶子节点存储主键值,需要回表查询
2. 什么是事务的隔离级别?MySQL 默认是哪个?
答案:
读未提交:可能脏读、不可重复读、幻读
读已提交:解决脏读(Oracle默认)
可重复读:解决脏读、不可重复读(MySQL默认)
串行化:解决所有问题,性能最低
3. Redis 持久化方式有哪些?区别是什么?
答案:
RDB:
定时快照,文件小,恢复快
可能丢失最后一次快照后的数据
AOF:
记录所有写操作,数据安全
文件大,恢复慢
混合持久化(Redis 4.0+):RDB + AOF,兼顾速度和数据安全
4. 如何用 Redis 实现分布式锁?要注意什么?
答案:
-- 加锁
SET lock_key unique_value NX EX 30-- 解锁(Lua脚本保证原子性)
if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1])
elsereturn 0
end
注意事项:
设置唯一value,防止误删其他线程的锁
设置过期时间,避免死锁
考虑锁续期问题
5. 缓存穿透、缓存雪崩、缓存击穿有什么区别?如何解决?
答案:
缓存穿透:查询不存在的数据
解决:布隆过滤器、缓存空对象
缓存雪崩:大量缓存同时失效
解决:设置不同的过期时间、集群部署
缓存击穿:热点key突然失效
解决:永不过期、互斥锁重建
🔹 微服务 & 分布式
1. 什么是服务注册与发现?Nacos 和 Eureka 有什么区别?
答案:
服务注册:服务提供者向注册中心注册自身信息
服务发现:服务消费者从注册中心获取服务列表
区别:
Nacos支持CP+AP模式切换,Eureka只支持AP
Nacos支持配置管理,Eureka不支持
Nacos健康检查更丰富
2. 如何保证微服务之间的调用安全?
答案:
使用HTTPS加密传输
JWT Token身份认证
API网关统一鉴权
服务间认证(如Spring Security OAuth2)
3. 什么是熔断和降级?Sentinel 是如何实现的?
答案:
熔断:服务故障时快速失败,避免雪崩
降级:服务压力大时关闭非核心功能
Sentinel实现:
基于滑动窗口统计QPS、响应时间等指标
根据规则进行流量控制、熔断降级
4. 你了解 Spring Cloud Gateway 的过滤器吗?如何使用?
答案:
spring:cloud:gateway:routes:- id: my_routeuri: http://example.orgfilters:- AddRequestHeader=X-Request-color, blue- PrefixPath=/api
全局过滤器:对所有路由生效
局部过滤器:对特定路由生效
🔹 项目 & 场景题
1. 你在项目中遇到的最大技术难点是什么?如何解决的?
参考答案:
"在博客系统的评论模块中,需要实现多级评论回复。最初使用递归查询,但性能很差。后来改用parent_id
字段维护层级关系,结合tree_path
字段存储评论路径,通过一次SQL查询获取所有评论,在内存中构建树形结构,性能提升了10倍以上。"
2. 如果系统出现 CPU 飙高,如何排查?
答案:
top
命令找到占用CPU高的进程top -Hp <pid>
找到具体线程jstack <pid> > stack.log
导出线程栈将线程ID转换为16进制,在stack.log中查找对应线程
分析代码定位问题(如死循环、频繁GC等)
3. 如何设计一个秒杀系统?
答案:
前端:静态化页面、按钮防重复点击
网关:限流、恶意请求过滤
服务层:
Redis预减库存(原子操作)
消息队列异步处理订单
令牌桶限流
数据层:数据库乐观锁、分库分表
4. 你如何保证接口的幂等性?
答案:
Token机制:先获取token,请求时携带token
唯一索引:防重复提交
状态机:只有特定状态才能执行操作
分布式锁:防并发重复提交
悲观锁/乐观锁:数据库层面控制