Java十道高频面试题(二)

JVM与性能调优

1. 线上服务CPU飙升到100%,你如何排查?

考察点:Linux命令、JDK工具链、实战排查思路。

参考答案

这是经典的线上故障排查题,核心思路是"定位高负载线程 -> 分析堆栈"。

  1. 定位进程 :使用 top 命令找到占用CPU最高的Java进程ID(PID)。
  2. 定位线程 :使用 top -Hp PID 查看该进程下所有线程的CPU占用情况,找到占用最高的线程ID(TID)。
  3. 进制转换 :将TID转换为16进制(printf "%x\n" TID),因为jstack日志中线程ID是十六进制的。
  4. 分析堆栈 :使用 jstack PID | grep 16进制TID -A 20 查看该线程的堆栈信息。
    • 情况A :如果是RUNNABLE状态且在执行业务代码,说明是算法复杂度高或死循环。
    • 情况B :如果是VM ThreadGC task thread,说明是频繁Full GC导致的(此时需结合jstat -gcutil验证)。
2. 什么是双亲委派模型?为什么要破坏它?(如Tomcat/SPI)

考察点:类加载机制、框架设计原理。

参考答案

  • 核心原理 :当一个类加载器收到加载请求时,它首先不会自己去尝试加载,而是把这个请求委派给父类加载器去完成。只有当父加载器反馈自己无法完成时(抛出ClassNotFoundException),子类才会尝试自己加载。
  • 好处 :保证Java核心类库的类型安全(例如用户无法自定义java.lang.String来替换核心类)。
  • 为什么要破坏(打破)
    • SPI机制(如JDBC) :JDBC接口在rt.jar(启动类加载器加载),而MySQL驱动在classpath(应用类加载器加载)。启动类加载器无法感知应用类加载器,因此使用线程上下文类加载器(ThreadContextClassLoader),让父类加载器请求子类加载器去加载驱动。
    • Tomcat :为了实现Web应用之间的隔离(不同应用加载不同版本的Spring),Tomcat自定义了WebAppClassLoader,优先加载WEB-INF下的类,打破了双亲委派。

数据库(MySQL)深度优化

3. 什么是"回表"?如何避免?(覆盖索引)

考察点:索引底层结构、SQL优化实战。

参考答案

  • 回表 :InnoDB的普通索引(二级索引)叶子节点存储的是主键ID 。如果查询的字段不包含在索引中,数据库需要先查普通索引拿到主键ID,再拿着主键ID去**聚簇索引(主键索引)**中查找完整的行数据。这个过程叫回表。
  • 避免回表(覆盖索引)
    • 如果查询的字段恰好是索引列(例如 select id, name from user where name = 'Alice',且name上有索引),则不需要回表。
    • 优化手段 :建立联合索引 。例如经常查询 select id, age, name,可以建立 (name, age) 的联合索引,这样查询时直接从索引树获取数据,无需回表。
4. 事务隔离级别与MVCC(多版本并发控制)原理

考察点:事务特性、并发一致性、Undo Log。

参考答案

  • 隔离级别
    • 读未提交:存在脏读。
    • 读已提交(RC):解决脏读,存在不可重复读。
    • 可重复读(RR,MySQL默认):解决脏读和不可重复读,通过MVCC很大程度上解决了幻读。
  • MVCC原理
    • 核心是隐藏字段 (DB_TRX_ID记录事务ID、DB_ROLL_PTR指向Undo Log)、Undo Log (版本链)和Read View(读视图)。
    • RC级别:每次Select都生成一个新的Read View,所以能读到最新提交的数据。
    • RR级别:第一次Select生成Read View,后续复用,保证同一事务内看到的数据一致。

Redis与分布式缓存

5. 缓存穿透、击穿、雪崩的区别及解决方案

考察点:高并发缓存场景、系统稳定性。

参考答案

  • 缓存穿透
    • 现象 :查询根本不存在的数据,请求直接打到数据库。
    • 解决
      1. 布隆过滤器:在缓存前加一层过滤。
      2. 缓存空对象:即使数据库没查到,也存一个null值到Redis(设置短过期时间)。
  • 缓存击穿
    • 现象 :某个热点Key突然过期,大量并发瞬间击穿到数据库。
    • 解决
      1. 互斥锁(Mutex):只让一个线程查库重建缓存,其他等待。
      2. 逻辑过期:不设置TTL,在Value里存过期时间,异步更新。
  • 缓存雪崩
    • 现象大量Key同时过期,或Redis宕机。
    • 解决
      1. 随机过期时间:在原有过期时间上加一个随机值。
      2. 高可用:Redis哨兵或集群模式。
6. 分布式锁的实现方案(Redis vs Zookeeper)

考察点:分布式协调、CAP权衡。

参考答案

  • Redis实现(Redlock)
    • 原理setnx key value + expire(原子性)。
    • 优点:性能极高(AP模型)。
    • 缺点:极端情况下(主从切换)可能丢失锁,导致安全性问题。
  • Zookeeper实现
    • 原理 :创建临时顺序节点。客户端监听前一个节点,前一个节点删除后,当前节点获得锁。
    • 优点:强一致性(CP模型),无死锁风险。
    • 缺点:频繁创建/删除节点,性能不如Redis。

微服务与架构设计

7. 分布式事务解决方案(CAP与BASE理论)

考察点:数据一致性、微服务架构。

参考答案

在微服务拆分后,本地事务失效,需要分布式事务。

  • 2PC(两阶段提交):强一致性,但性能差,阻塞资源(如XA协议)。
  • TCC(Try-Confirm-Cancel)
    • 原理:应用层的两阶段。Try阶段预留资源,Confirm提交,Cancel回滚。
    • 场景:对一致性要求高且并发高的核心业务(如支付)。
  • 最终一致性(BASE理论)
    • 本地消息表/MQ事务消息:先执行本地事务,发送消息,下游消费。如果失败则重试。
    • Seata(AT模式):阿里开源,基于Undo Log自动回滚,对代码无侵入,适合大多数业务。
8. 消息队列(MQ)如何保证消息不丢失?

考察点:消息可靠性、系统设计。

参考答案

需要从三个阶段保证:

  1. 生产者阶段
    • 开启Confirm机制 (RabbitMQ)或ACK机制(Kafka/RocketMQ)。只有Broker确认收到消息,生产者才认为发送成功。
  2. MQ服务端(Broker)阶段
    • 持久化:开启消息持久化(同步刷盘或异步刷盘),防止宕机丢失。
    • 多副本:主从同步,防止单点故障。
  3. 消费者阶段
    • 手动ACK:关闭自动ACK。业务逻辑执行成功后,再手动发送ACK给Broker。如果处理失败,返回NACK触发重试。

算法与数据结构(实战类)

9. 如何设计一个限流算法?(令牌桶 vs 漏桶)

考察点:高并发防护、算法应用。

参考答案

  • 令牌桶算法
    • 原理:固定速率向桶中放入令牌,桶有容量上限。请求处理前需获取令牌,无令牌则拒绝或等待。
    • 特点 :允许突发流量(只要桶里有令牌)。
    • 应用:Guava RateLimiter,适合保护下游服务同时允许短时间突发。
  • 漏桶算法
    • 原理 :水(请求)流入桶,桶底以固定速率漏水(处理)。桶满则溢出(拒绝)。
    • 特点强行限制流出速率,平滑流量。
    • 应用:适合对流出流量有严格限制的场景(如短信发送接口)。
10. 常见的排序算法中,哪些是稳定的?快排的时间复杂度?

考察点:基础算法功底。

参考答案

  • 稳定性 :指排序后,相同元素的相对位置不发生改变。
    • 稳定:冒泡排序、插入排序、归并排序。
    • 不稳定:快速排序、选择排序、堆排序。
  • 快速排序
    • 平均时间复杂度: O(nlog⁡n)O(nlogn) 。
    • 最坏情况: O(n2)O(n2) (当数组已有序,且每次选第一个为基准时)。
    • 优化:随机选取基准值,或使用"三数取中"法。
相关推荐
叼烟扛炮1 小时前
C++ 知识点23 类模板
开发语言·c++·算法·类模版
java1234_小锋1 小时前
Spring AI 2.0 开发Java Agent智能体 - 会话记忆(Chat Memory)
java·人工智能·spring
Sylvia33.1 小时前
世界杯数据链路解析:从球场传感器到终端推送的毫秒级架构
java·前端·python·架构
xlq223221 小时前
53.tcp socket
linux·服务器·开发语言·网络·网络协议·tcp/ip
Royzst1 小时前
Lambda 算法基础 集合概述
java·开发语言
SmallBambooCode1 小时前
【人工智能】【Python】离线环境下huggingface预训练权重导入流程
开发语言·人工智能·python
Yeh2020581 小时前
Mybatis笔记一
java·笔记·mybatis
likerhood1 小时前
Java 动态代理深度解析:从“为什么“到“底层原理“
java