Java面试场景题实战:并发扣库存、OOM排查与事务失效全解析

Java面试场景题并发编程
于 2026-08-30 04:15:19 修改
·本内容遵循CC 4.0 BY-SA版权协议

这次我们直接聊 Java 面试里最容易被“场景题”卡住的问题。刷过八股文的人不少,但一到“线上 OOM 怎么排查”“车位相机上报延迟怎么处理”“订单并发扣库存怎么保证不超卖”这类题目,很多人就接不住了。原因不是基础差,而是没有把 Java 知识放到真实项目里串过一遍。这篇文章会用我们经常接触到的真实业务场景,把 2026 年面试逃不掉的 Java 经典真题重新拆一遍——不是背诵答案,而是讲清楚“面试官为什么问、项目里怎么用、回答时怎么说”。

核心内容分成三块:

  1. 高频场景题拆解:并发编程、JVM 调优、集合源码、Spring 事务、消息队列、接口幂等等。
  2. 结合项目实战:包括停车场上车牌识别相机对接、前后端分离项目、OOM 排查、批量任务处理等。
  3. 一套可以直接背的 7 天刷题计划:每天一个专题,把场景题从“看答案”变成“能开口讲”。

如果你正在准备 Java 面试,或者已经有工作经验但面试时容易被项目细节问倒,这篇文章建议直接收藏。

1. 面试场景题,和八股文到底差在哪

很多人准备面试时有一个误区:背了几十道 Java 八股文,就觉得自己准备好了。结果面试官换了个问法,问“你的项目里 Redis 缓存穿透是怎么解决的”,立刻懵住。

八股文的问题是:它是知识点的孤立记忆

场景题的核心是:用项目里的真实问题来验证你是否真的理解这个知识点

举一个最常见的例子:

面试官问:HashMap 底层数据结构是什么?

这是八股文。会背的人都能答上来:数组 + 链表 + 红黑树,负载因子 0.75,扩容时重新计算哈希桶位置。

但如果换成场景题:

面试官问:你的项目里用 HashMap 存储数据,结果测试环境 CPU 飙高,你怀疑是哈希冲突严重,你会怎么排查?怎么调整?

这就是场景题。它要求你不仅知道 HashMap 的原理,还要知道:

  • HashMap 在并发场景下会有什么问题。
  • 什么情况会导致哈希冲突严重。
  • 如何通过调整初始容量和负载因子来优化。
  • ConcurrentHashMap 和 HashMap 的使用边界。

从面试官的角度看,场景题能过滤掉“背答案”的人。从候选人的角度看,场景题才是真正体现技术深度的机会。

所以这篇文章不会花时间背八股文,而是把高频的 Java 经典面试真题,全部放到项目实战场景里重新过一遍。每个场景都按“题目 -> 问题分析 -> 项目应用 -> 回答思路 -> 代码/配置示例”的结构展开。

2. 高频场景题速览:面试官最爱问的 6 类

根据近两年的面试趋势,Java 面试场景题集中在下面 6 个方向。不管你是应届生还是 3 年左右经验的开发,这 6 类都是必刷项。

场景类型 典型案例 涉及核心知识点 常见出题方式
并发编程 订单并发扣库存 synchronized、ReentrantLock、CAS、ThreadPoolExecutor 项目里怎么样保证不超卖
JVM 性能 线上 OOM 排查 堆内存、GC 日志、MAT、jstack、jmap 你的项目遇到过 OOM 吗,怎么排查的
集合源码 停车场车牌缓存设计 HashMap、ConcurrentHashMap、ArrayList、LinkedList 为什么不直接用 HashMap 存设备状态
Spring 原理 事物失效问题 @Transactional 传播行为、AOP、动态代理 一个方法调另一个方法,事务为什么没生效
分布式与中间件 MQ 消息丢失/重复消费 Kafka/RabbitMQ、幂等、重试 消息发到 MQ 后消费者挂了怎么办
项目架构 前后端分离接口鉴权 JWT、Spring Security、拦截器、过滤器 你的项目登录态是怎么设计的

下面逐个拆解。

3. 并发编程场景题:订单系统扣库存,怎么保证不超卖

3.1 题目还原

面试官:你的项目里有一个秒杀接口,1000 件库存,5000 个人同时抢。你的代码是 if (stock > 0) { stock--; },结果库存变成负数了。你会怎么改?

3.2 问题分析

这是一个非常经典的并发场景题。考点不是 synchronized 的用法,而是你有没有在真实项目里处理过并发问题

先看原始代码:

JAVA
// 错误示例:非原子操作
if (stock > 0) {
stock--;
// 生成订单...
}

这段代码的问题很明显:if (stock > 0)stock-- 不是原子操作。两个线程同时读到 stock=1,都通过了 if 判断,然后都执行了减一,最后 stock 变成 -1。

3.3 项目里的正确解法

在实际项目中,扣库存通常有三种方案:

方案一:数据库乐观锁

SQL
-- 乐观锁:版本号方式
UPDATE product
SET stock = stock - 1,
version = version + 1
WHERE id = 123
AND stock > 0
AND version = #{oldVersion};

执行结果影响行数为 1,说明扣减成功;为 0,说明库存不足或版本冲突,直接返回失败。

方案二:使用 Redis 原子操作

JAVA
// 扣减库存前,先用 Redis 做原子扣减
Long stock = redisTemplate.opsForValue().decrement("product:stock:123", 1);
if (stock != null && stock >= 0) {
// 扣减成功,异步落库
} else {
// 扣减失败,库存不足,需要回补 Redis
redisTemplate.opsForValue().increment("product:stock:123", 1);
}

注意:Redis 扣减成功后,数据库落库也要使用乐观锁或唯一约束来兜底,防止 Redis 和数据库数据不一致。

方案三:分布式锁

适合并发量极大且需要强一致的场景,比如使用 Redisson:

JAVA
RLock lock = redissonClient.getLock("stock:lock:123");
boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
if (!locked) {
// 获取锁失败,提示稍后重试
}
try {
int stock = productMapper.getStock(123);
if (stock > 0) {
productMapper.decreaseStock(123);
// 创建订单...
}
} finally {
lock.unlock();
}

3.4 回答思路

回答这类场景题时,不要直接摔代码,按下面这个顺序说:

  1. 先说问题本质:check-then-act 不是原子的,导致超卖。
  2. 给出方案对比:数据库乐观锁适合低频、一致性要求高的场景;Redis 原子扣减适合高并发秒杀场景;分布式锁适合强一致性业务。
  3. 说你在项目里最终用了哪种,以及为什么。
  4. 补充兜底方案:比如数据库最终一致性校验、定时任务对账。

这套回答思路能覆盖 80% 的并发场景题。

3.5 扩展:线程池为什么不能被无脑用

并发场景里另一个高频点就是线程池。面试官通常会追问:

为什么不直接 new Thread()?线程池的核心参数怎么设置?

回答核心:

  • new Thread() 每次都会创建新线程,线程生命周期不可控,频繁创建销毁开销大。
  • 线程池可以复用线程、控制并发数、管理队列。
  • 核心参数有 7 个:核心线程数、最大线程数、空闲存活时间、时间单位、工作队列、线程工厂、拒绝策略。

在一个实际的项目中,线程池通常配置如下:

JAVA
ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, // 核心线程数
8, // 最大线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000), // 工作队列
new ThreadFactoryBuilder().setNameFormat("business-pool-%d").build(),
new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略

拒绝策略这块,面试官很喜欢往深了问:

  • AbortPolicy:抛出 RejectedExecutionException,默认策略。
  • CallerRunsPolicy:由调用线程直接执行,适合不希望丢弃任务的场景。
  • DiscardPolicy:静默丢弃。
  • DiscardOldestPolicy:丢弃队列中最旧的任务,然后重新尝试提交。

项目里如果任务不能丢,建议用 CallerRunsPolicy 或自定义拒绝策略,配合告警通知。

4. JVM 实战场景题:线上 OOM 了,你第一步做什么

4.1 题目还原

面试官:你的 Spring Boot 项目运行了几天后,突然报 java.lang.OutOfMemoryError: Java heap space,服务直接挂掉。你从哪些方面排查?

4.2 问题分析

OOM 是 Java 面试里最常出现的场景题之一。它考的是你是否真的遇到过线上故障,并且有完整的排查思路

先看常见的 OOM 类型:

错误类型 含义 常见场景
Java heap space 堆内存溢出 大对象过多、内存泄漏
GC overhead limit exceeded GC 频繁且回收效果差 堆太小、对象存活时间过长
Metaspace 元空间溢出 动态生成类过多
Unable to create new native thread 线程数达到系统上限 无限创建线程、线程池参数不合理

4.3 完整排查步骤

第一步:保留现场。

在启动脚本中加上 JVM 参数,让 OOM 时自动导出堆转储文件:

BASH
java -Xms2g -Xmx2g \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/data/logs/app-oom.hprof \
-Xloggc:/data/logs/gc.log \
-jar app.jar

第二步:查日志。

先用 dmesg 或系统监控查看进程是否被操作系统杀掉,再用 jmap -heap 看当前堆的使用情况。

BASH
jmap -heap $(pgrep -f app.jar)

第三步:分析堆转储文件。

app-oom.hprof 下载到本地,用 MAT 或 VisualVM 打开。重点看:

  • 大对象列表:哪些对象占据了 80% 以上的堆内存。
  • 支配树:对象的引用链是谁。
  • 线程栈:哪些线程在持续创建对象。

第四步:定位代码问题。

比如最常见的场景:用 List 批量查询数据库后,把所有结果一次性 load 到内存,数据量大了就 OOM。

JAVA
// 反例:一次性装载大量数据
List<Order> orders = orderMapper.selectAll();
for (Order order : orders) {
// 处理...
}

优化方案是分批处理或使用游标查询:

JAVA
// 改进:分批查询,控制单批数据量
int pageSize = 500;
int pageNum = 1;
List<Order> orders;
do {
orders = orderMapper.selectByPage(pageNum, pageSize);
for (Order order : orders) {
// 处理...
}
pageNum++;
} while (orders.size() == pageSize);

4.4 回答思路

回答 OOM 排查题的推荐结构:

  1. 先说调整启动参数,保留现场。
  2. 再说查 GC 日志和系统监控,确认是堆内存还是线程问题。
  3. 然后说用 MAT 分析堆转储,定位大对象。
  4. 最后说项目里常见的优化手段:分批处理、升级内存、缩减缓存。

这一套流程说完,面试官能明确感受到你有实战经验。

4.5 扩展:CPU 飙高怎么排查

OOM 场景经常还会带一个兄弟问题:

服务 CPU 使用率 100%,怎么定位是哪个线程的问题?

完整命令流程:

BASH
# 1. 找到 Java 进程 PID
jps -l
 
# 2. 查看哪个线程占用 CPU 高
top -Hp PID
 
# 3. 将线程 ID 转为 16 进制
printf "%x\n" 12345
 
# 4. 导出线程栈,找对应线程
jstack PID > thread_dump.txt

拿到线程栈后,重点看线程状态和堆栈调用:如果是 RUNNABLE 并且一直在执行业务代码,说明是计算密集型任务;如果是 WAITING 且大量堆积,可能是线程池队列过长或死锁。

5. 集合源码场景题:停车场车牌识别相机状态怎么高效缓存

5.1 场景还原

这是一个真实项目里的问题。停车场项目里需要对接海康、大华等主流车牌识别相机,相机通过 MQTT 协议上报车辆入场、出场事件和实时状态。项目需要缓存每台相机的在线状态、最近上报时间、当前抬杆状态等。

面试官问:

你会用什么集合来存这些设备状态?为什么不用 ArrayList?为什么不用 HashMap?

5.2 问题分析

这个题目一举三得:考了集合特性、考了并发安全、考了项目设计。

先看最直接的方案:用 HashMap。

JAVA
Map<String, DeviceStatus> deviceStatusMap = new HashMap<>();
deviceStatusMap.put("camera_001", status);

问题来了:

  • HashMap 是非线程安全的。MQTT 回调线程和业务查询线程同时操作 map,会出问题。
  • 需要频繁读取和更新设备状态,HashMap 在扩容时会重新哈希,性能抖动。
  • 如果要按照最后上报时间排序,HashMap 无能为力。

所以项目里的正确选择可能有三种:

方案一:ConcurrentHashMap

JAVA
Map<String, DeviceStatus> deviceStatusMap = new ConcurrentHashMap<>();

优点:线程安全、读性能高。适合高频读写状态,但不支持排序。

方案二:使用带过期时间的本地缓存 Caffeine

JAVA
Cache<String, DeviceStatus> cache = Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.recordStats()
.build();

优点:自动处理设备离线情况,5 分钟没有上报自动过期,配合定时巡检更合理。

方案三:使用 Redis Hash

JAVA
redisTemplate.opsForHash().put("device:status", "camera_001", JSON.toJSONString(status));

优点:分布式部署时多个实例共享状态;缺点:多一次网络 IO,实时性要求极高时可能有延迟。

5.3 回答思路

回答这类集合选型题时,不要只说“用 ConcurrentHashMap”,要把为什么说清楚:

  1. MQTT 回调是多线程的,HashMap 不安全。
  2. 设备状态需要频繁读写和过期清理,Caffeine 更合适。
  3. 如果是分布式部署,需要多个服务共享状态,用 Redis。
  4. 补充一句:ArrayList 不适合做键值查询,它有顺序,但查询指定设备要遍历,复杂度 O(n)。

把选择过程和思考维度展示出来,面试官会认为你真正做过项目,而不是背了“ArrayList 查询慢,HashMap 查询快”的口诀。

5.4 扩展:HashMap 底层和并发问题

如果继续往下追,面试官一定会问 HashMap 的底层原理:

  • JDK 1.7:数组 + 链表,头插法,并发扩容时会成环。
  • JDK 1.8:数组 + 链表 + 红黑树,尾插法,链表长度超 8 且数组长度超 64 时转为红黑树。
  • 负载因子默认 0.75,扩容后数组长度翻倍。
  • HashMap 的 key 为 null 时,存放在数组下标 0 的位置。

高频追问:为什么链表长度超过 8 才转红黑树?

回答思路:源码注释里说明,遵循泊松分布概率,链表长度达到 8 的概率极低(约千万分之六),在绝大多数场景下链表长度远小于 8。转红黑树是为了极端哈希冲突情况下,仍然能保证查询效率从 O(n) 降到 O(log n)。

6. Spring 事务场景题:一个方法里调另一个方法,事务为什么不生效

6.1 题目还原

面试官:你的 Service 里有一个 createOrder() 方法加了 @Transactional,它调用了同类的 deductStock() 方法,过程中抛了异常,但库存还是扣了。为什么?怎么解决?

6.2 问题分析

这是一个非常高频的 Spring 事务失效场景。

核心原因是:@Transactional 默认是通过 Spring AOP 代理实现的。同类内部调用时,this.deductStock() 走的是原始对象,不是代理对象,所以事务注解不生效。

JAVA
@Service
public class OrderService {
 
public void createOrder(Order order) {
// 直接调用同类方法,事务不生效
deductStock(order.getProductId());
orderMapper.insert(order);
}
 
@Transactional
public void deductStock(Long productId) {
stockMapper.decrease(productId);
throw new RuntimeException("库存扣减失败,回滚");
}
}

6.3 解决方案

方案一:拆分成两个 Bean,单独注入。

JAVA
@Service
public class OrderService {
 
private final StockService stockService;
 
public OrderService(StockService stockService) {
this.stockService = stockService;
}
 
public void createOrder(Order order) {
stockService.deductStock(order.getProductId());
orderMapper.insert(order);
}
}
 
@Service
public class StockService {
 
@Transactional
public void deductStock(Long productId) {
stockMapper.decrease(productId);
throw new RuntimeException("库存扣减失败,回滚");
}
}

方案二:使用 AopContext.currentProxy() 获取代理对象。

JAVA
public void createOrder(Order order) {
OrderService proxy = (OrderService) AopContext.currentProxy();
proxy.deductStock(order.getProductId());
orderMapper.insert(order);
}

注意:使用 AopContext 必须在启动类或配置类中增加 @EnableAspectJAutoProxy(exposeProxy = true)

方案三:自己注入自己(实际上不推荐,存在循环依赖风险)。

6.4 扩展:事务传播行为

如果面试官继续追问事务传播行为,项目中最常用的有三个:

  • REQUIRED:默认,如果当前没有事务就新建一个,如果有就加入当前事务。
  • REQUIRES_NEW:挂起当前事务,新建一个独立事务。
  • NESTED:嵌套事务,内层回滚不影响外部事务,外部回滚会连同内层一起回滚。

在项目里一个典型场景:记录操作日志时,即使主业务失败,日志也要记录成功,这时就需要 REQUIRES_NEW

JAVA
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveOperateLog(Log log) {
logMapper.insert(log);
}

但要注意:REQUIRES_NEW 会开启新事务,意味着它不参与外部事务的回滚。如果日志和业务数据需要保持一致,就不能用这个传播级别。

6.5 回答思路

关于事务失效,这个知识点涉及 6 个常见场景,可以一次说完:

  1. 同类内部调用导致代理失效。
  2. @Transactional 加在非 public 方法上。
  3. 异常被 try-catch 吞掉。
  4. 数据库引擎不支持事务(比如 MyISAM)。
  5. 使用了 this 调用而非代理对象。
  6. 多线程调用,事务无法跨线程传播。

这样回答既有深度,又体现了系统性认知,面试官很容易记住你。

7. 中间件场景题:车位相机通过 MQTT 上报消息,消息积压了怎么处理

7.1 场景还原

停车场项目里,海康、大华等车牌识别相机通过 MQTT 协议上报车辆进出事件,后端服务订阅消息并将事件写入数据库、推送通知等。某次活动期间,大量车辆同时进出,MQTT 消息积压严重,数据库写入延迟,部分消息丢失。

面试官问:

你负责的消息链路出现积压、丢失,会怎么排查和处理?

7.2 问题分析

这是一个完整的消息中间件实战问题,涉及消息队列的三大核心问题:削峰填谷、可靠性、幂等

先分析积压的原因:

  • 生产者的发送速度远大于消费者的处理速度。
  • 消费者处理逻辑太重,比如每条消息都同步写数据库。
  • 消费者挂了或线程数配置过小。

7.3 项目里的处理方案

方案一:引入消息队列削峰。

如果原本是相机 -> 后端服务直连,可以改为相机 -> MQ -> 后端服务。使用 Kafka 或 RabbitMQ 做缓冲,后端服务按照自己的处理能力消费。

YAML
spring:
kafka:
bootstrap-servers: 192.168.1.10:9092
consumer:
group-id: parking-event-group
enable-auto-commit: false
max-poll-records: 200

方案二:批量消费,减少数据库 IO。

将 100 条消息攒成一批,再统一写库:

JAVA
@KafkaListener(topics = "parking-event", groupId = "parking-event-group")
public void onMessage(List<ConsumerRecord<String, String>> records) {
List<ParkingEvent> events = records.stream()
.map(record -> JSON.parseObject(record.value(), ParkingEvent.class))
.map(this::convertToEntity)
.collect(Collectors.toList());
// 批量插入
parkingEventMapper.batchInsert(events);
}

方案三:处理消息丢失问题。

MQTT QoS 等级可以调整为 1 或 2,同时消费端要开启手动 ACK:

JAVA
@KafkaListener(topics = "parking-event", groupId = "parking-event-group")
public void onMessage(ConsumerRecord<String, String> record, Acknowledgment ack) {
try {
process(record);
ack.acknowledge(); // 处理成功后手动确认
} catch (Exception e) {
// 记录失败日志,进入死信队列或重试
saveToDeadLetter(record);
ack.acknowledge(); // 避免消息无限重试阻塞后续消息
}
}

方案四:解决重复消费问题。

消息队列保证的是 at least once,也就是至少一次投递,这会导致重复消费。所以消费端必须做幂等处理。最简单的方式是用唯一业务 ID(如车牌号 + 入场时间)做去重表:

SQL
CREATE TABLE parking_event_dedup (
event_id VARCHAR(64) PRIMARY KEY,
create_time DATETIME
);

每次处理前先查去重表,存在则跳过:

JAVA
if (dedupMapper.exists(eventId)) {
// 已处理,直接跳过
return;
}
// 执行业务逻辑,同时插入去重记录
dedupMapper.insert(eventId);

7.4 回答思路

消息中间件场景题的完整思路:

  1. 先区分是积压、丢失还是重复消费。
  2. 积压:看消费速度和生产速度的差距,优化消费者逻辑、批量处理、增加分区和消费者数量。
  3. 丢失:从生产端、MQ 端、消费端三段排查,确认 ACK 机制。
  4. 重复:数据库唯一约束或业务 ID 去重。

这个套路的适用性很广,不只是 MQTT,Kafka、RabbitMQ 相关题目都可以这么组织。

8. 项目架构场景题:前后端分离项目的登录鉴权怎么设计

8.1 场景还原

目前很多项目都是前后端分离架构,前端用 Vue3 或 Vue2,后端用 Spring Boot。用户登录后,前端需要携带凭证请求后端接口,后端需要校验凭证并返回用户信息。

面试官问:

你的项目登录态是怎么保存的?用 Session 还是 Token?Token 过期了怎么办?

8.2 方案对比

Session 方案

  • 服务端保存 Session,客户端保存 Cookie 中的 JSESSIONID。
  • 优点:实现简单,Spring Boot 原生支持。
  • 缺点:分布式部署时需要解决 Session 共享问题,需要引入 Spring Session + Redis。

JWT 方案

  • 服务端生成签名字符串,客户端保存,每次请求携带在 Header 里。
  • 优点:无状态、适合分布式和微服务。
  • 缺点:无法服务端主动失效,token 泄露后只能等过期。

项目里常用的是 JWT + Redis 组合方案:

JAVA
// 登录成功后生成 JWT
String token = Jwts.builder()
.setSubject(userId.toString())
.claim("username", username)
.setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000))
.signWith(secretKey)
.compact();
 
// 将 token 存入 Redis,设置过期时间
redisTemplate.opsForValue().set("login:token:" + userId, token, 24, TimeUnit.HOURS);

然后在拦截器或过滤器中校验:

JAVA
@Component
public class JwtInterceptor implements HandlerInterceptor {
 
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!(handler instanceof HandlerMethod)) {
return true;
}
String token = request.getHeader("Authorization");
if (StringUtils.isEmpty(token)) {
throw new BusinessException("未登录");
}
// 解析 token,校验签名,检查用户是否在 Redis 中存在
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
// 放入 ThreadLocal 或 request attribute
request.setAttribute("userId", claims.getSubject());
return true;
}
}

8.3 扩展:权限控制与接口幂等

登录鉴权之后,面试官还会顺着问权限控制:

  • RBAC:用户 -> 角色 -> 权限模型。
  • Spring Security 的 @PreAuthorize("hasRole('ADMIN')") 注解。
  • 接口权限:不同角色可以看到不同的接口。

另外,在前后端分离项目中,还有一个高频场景是接口幂等

用户重复提交订单,导致产生多条重复订单。怎么解决?

常用方案:

  1. 前端按钮防抖,置灰。
  2. 后端使用 token 机制:请求前先从服务端获取一个幂等 token,提交时校验并删除,删除成功说明第一次提交,失败说明重复提交。
JAVA
// 生成幂等 token
String idempotentToken = UUID.randomUUID().toString();
redisTemplate.opsForValue().set("idempotent:" + idempotentToken, "1", 10, TimeUnit.MINUTES);
 
// 提交时校验
Boolean deleted = redisTemplate.delete("idempotent:" + idempotentToken);
if (!Boolean.TRUE.equals(deleted)) {
throw new BusinessException("重复提交");
}

9. 7 天 Java 面试场景题刷题计划

如果你现在离面试还有一周左右,建议按下面这个计划刷题。每一天都围绕一个核心专题,不仅看答案,还要动手写一写验证一下。

第 1 天:Java 基础与集合

重点场景题:

  • HashMap 与 ConcurrentHashMap 在项目中的选型
  • ArrayList 扩容机制和实际项目中的坑
  • 快速排序和冒泡排序的手写与复杂度比较
  • Lambda 表达式和函数式接口在项目中的使用场景

建议动作:手写一个多线程环境下使用 HashMap 出错的 Demo,再改成 ConcurrentHashMap 验证问题解决。

第 2 天:并发编程与线程池

重点场景题:

  • 订单并发扣库存怎么保证不超卖
  • 线程池参数怎么设置
  • 项目中遇到死锁怎么排查
  • volatile 和 synchronized 的使用场景区别

建议动作:手动写一个线程池,模拟任务队列堆积,观察拒绝策略触发效果。

第 3 天:JVM 性能调优

重点场景题:

  • 线上 OOM 怎么排查
  • CPU 100% 怎么定位
  • 常用的 JVM 参数有哪些
  • GC 日志怎么看

建议动作:本地启动一个 Spring Boot 项目,故意制造内存泄漏场景,用 jmap 导出堆转储,用 MAT 分析。

第 4 天:Spring 与 MyBatis

重点场景题:

  • 事务注解为什么不生效
  • Bean 的初始化过程
  • MyBatis 中 #{} 和 ${} 的区别
  • Spring Boot 的自动配置原理

建议动作:写一个 Controller -> Service -> Mapper 三层结构,测试事务回滚和传播行为。

第 5 天:中间件与消息队列

重点场景题:

  • 消息丢失怎么处理
  • 重复消费怎么处理
  • 消息积压怎么解决
  • Kafka 分区和消费者的关系

建议动作:搭建一个简单的 Kafka 单机环境,写生产者消费者 Demo,模拟重复消费和手动 ACK。

第 6 天:项目架构与业务设计

重点场景题:

  • 前后端分离接口鉴权设计
  • 接口幂等怎么做
  • 数据库分库分表的场景和方案
  • MQTT 对接相机等硬件设备时的心跳与离线设计

建议动作:整理自己项目里的架构图,把登录流程、接口调用链、异常处理流程用文字描述清楚。

第 7 天:全真模拟面试

重点关注题:

  • 自我介绍,一定要包含项目职责和亮点。
  • 项目中最有挑战的问题是什么,怎么解决的?提前准备一个 OOM 排查或并发扣库存的完整故事。
  • 如果重做一次项目,哪些设计会优化?

建议动作:找朋友或同事帮你模拟面试,至少模拟两轮,每轮 30 分钟以上。重点练表达流畅度,不要只背答案。

10. 常见面试场景题自测清单

下面这份清单,你可以在面试前 1 天快速过一遍。任何一条不能顺畅回答超过 5 分钟,就回去补一下。

题目 核心考点 回答关键要点
多线程同时扣库存怎么防止超卖 并发安全 乐观锁、Redis 原子扣减、分布式锁对比
项目里遇到 OOM 怎么排查 JVM 调优 保留现场、jmap、MAT 分析、分批处理
HashMap 和 ConcurrentHashMap 区别 集合原理 线程安全、锁粒度、扩容机制
事务注解失效的原因有哪些 Spring 原理 同类调用、异常被吞、代理机制
消息重复消费怎么解决 中间件设计 业务 ID 去重、数据库唯一约束
JWT 和 Session 怎么选 项目架构 无状态、分布式、失效机制
线程池拒绝策略有哪些 并发编程 四种策略和适用场景
MyBatis 的 #{} 和 ${} 区别 ORM 框架 预编译、SQL 注入
接口幂等怎么设计 业务设计 前端防抖、幂等 token、状态机
设备离线或心跳超时怎么处理 物联网/硬件对接 心跳机制、过期清理、状态补偿

11. 面试答题时最容易踩的 5 个坑

11.1 只答结论,不说过程

比如问“Redis 为什么快”,不能只回答“因为内存操作”。要补充:单线程避免上下文切换、IO 多路复用、高效的数据结构、渐进式 rehash。

11.2 背答案痕迹太重

如果说到 ConcurrentHashMap 时,把源码注释背了一遍,但项目里从来没碰到过并发问题,面试官一眼就能看出来。最好结合自己的项目:在停车场的设备状态缓存场景里,哪些数据需要并发安全,为什么。

11.3 不区分“知道”和“做过”

回答时尽量用“我在项目里做过”“当时遇到了什么问题,我用了什么方案”。即使项目是团队合作或课程实战项目,也能体现你动手验证过,而不只是看资料。

11.4 展开得不够

比如被问“接口幂等怎么实现”,只说“用 token”是不够的。至少要提到:token 的生成时机、存储位置、校验方式、并发场景下的原子性、token 过期时间。

11.5 不会主动收尾

回答完之后,用一两句话总结你的设计思路。例如:“幂等的核心是保证同一个请求只被处理一次,前后端配合,前端做按钮防抖,后端做 token 去重,数据库加唯一约束兜底。”这样会给面试官留下结构化、有工程思维的印象。

12. 结合项目实战:把场景题串起来讲

最后给一个“组合拳”案例,把 8 个高频考点串到一个真实项目场景里。这是你在面试中非常加分的表达方式。

我曾经做过一个停车场车牌识别系统,车辆入场时,海康相机通过 MQTT 上报车辆入场事件。后端订阅消息后,核心业务流程是:解析消息 -> 计算停车时长/费用 -> 更新缓存 -> 推送通知 -> 写入数据库。

围绕这个项目,可以应对下面的连环追问:

追问一:并发上报,怎么保证消息不丢?

回答:通过 MQTT QoS 1 和消费者手动 ACK,消息消费成功后才提交 offset。同时增加死信队列,失败的消息进入死信并告警。

追问二:消息重复上报怎么办?

回答:数据库表加唯一索引 (camera_code, plate_number, entry_time),重复插入直接 SQL 层拦截,业务层再配合 Redis 布隆过滤器做前置判断。

追问三:设备状态缓存用什么数据结构?

回答:使用 Caffeine 本地缓存存储每台相机的在线状态,过期时间 5 分钟。分布式环境切 Redis Hash。缓存与数据库通过异步任务保持最终一致性。

追问四:高峰期大量车辆同时进出,数据库压力大怎么办?

回答:MQ 先削峰,消费者开启批量消费(500 条一批),写库前先聚合,减少 IO 次数。如果数据量更大,按停车场 ID 分库分表。

追问五:如果消息处理时发生 OOM,怎么排查?

回答:启动参数加 -XX:+HeapDumpOnOutOfMemoryError,OOM 时自动导堆转储,用 MAT 分析是哪个对象占用过高。最终定位到日志对象或者一次性加载的数据,改成批量处理。

这样一套串讲下来,你已经把并发、消息队列、JVM、集合选型、幂等设计全部覆盖了。面试官会认为你是一位真正在项目中解决问题的人,而不是只会背答案的候选人。

13. 总结与下一步

Java 面试场景题的核心不是“刷得越多越好”,而是把一个场景从问题出现到方案落地完整讲清楚。如果你时间有限,优先准备下面 5 个:

  1. 订单并发扣库存怎么保证不超卖。
  2. 线上 OOM 怎么排查和解决。
  3. 事务注解失效的原因有哪些。
  4. 消息队列重复消费和积压怎么处理。
  5. 前后端分离接口鉴权和幂等怎么设计。

接下来要做的就是行动:周末先把 JVM 排查流程在本地过一遍,再把手头项目里的并发、缓存、消息链路整理成文字。能力强不强,面试官问两个场景题就知道了。把这篇文章里每一道题都自己讲一遍,再去面试,拿 Offer 的概率会大很多。

一次OOM问题排查过程实战记录
OOM 问题排查过程实战记录一、OOM 问题排查过程概述在 Java 应用程序中,OutOfMemoryError 是一种常见的异常,它可能是由于堆空间不足、永久代空间不足或是无法分配对象所引发的。
weixin_38681646
4263
Java OOM场景与排查[项目源码]
交换空间耗尽则和系统的物理内存虚拟内存配置有关。针对每种OOM场景,文章提供了相应的排查手段。
1
要资深java程序员面试场景题
本文档为资深Java开发工程师面试准备了详细的场景题目录,涵盖系统设计、JVM性能优化、并发编程、框架源码解析、分布式系统、数据库ORM、安全合规以及工程实践等关键领域。每个部分都包含具体的问题和示例,旨在帮助候选人全面准备面试
安大林的码路
Java 最常见 200+ 面试全解析:面试必备208
Java作为全球最主流的面向对象编程语言之一,其生态庞大、应用广泛,从企业级后端系统(如银行核心系统、电商中台)、大数据平台(Hadoop/Spark部分模块)、Android原生开发,到云原生微服务架构(Spring Cloud)、高并发中间件(RocketMQ、Dubbo)等,无不深度依赖Java技术栈。因此,“Java最常见200+面试全解析:面试必备208”这一资源并非简单罗列问题,而是系统性覆盖了Java工程师从初级到高级所必须掌握的**八维核心知识体系**,构成了一套完整的Java能力评估进阶路线图。首先,在**JVM底层机制**层面,题目深入考察类加载双亲委派模型的原理破坏场景(如SPI机制、Tomcat自定义ClassLoader)、运行时数据区(方法区/元空间演进、堆内存分代结构)、字节码指令集(如monitorenter/monitorexit对应synchronized实现)、以及GC算法本质——不仅要求背诵CMS、G1、ZGC的回收阶段,更强调对“三色标记法”“SATB写屏障”“增量更新”等底层并发标记策略的理解,以及如何通过-XX:+PrintGCDetails、jstat、jmap、jstack、Arthas等工具进行线上GC调优与OOM根因分析。其次,在**多线程与并发编程**领域,题目超越基础的synchronized和volatile用法,直击JMM内存模型三大特性(原子性、可见性、有序性)的硬件级实现(MESI缓存一致性协议、StoreLoad屏障)、AQS抽象队列同步器的CLH变种设计、ReentrantLock公平/非公平锁的statewaitStatus状态流转、CountDownLatch/CyclicBarrier/ForkJoinPool的底层CAS+volatile协作机制,以及Java 8新增的StampedLock乐观读锁在高读低写场景下的性能优势。第三,**集合框架**部分绝非仅限于ArrayListLinkedList区别,而是深入HashMap的红黑树转换阈值(TREEIFY_THRESHOLD=8UNTREEIFY_THRESHOLD=6的协同设计)、resize扩容时的链表高位低位拆分逻辑、ConcurrentHashMap 1.8的CAS+synchronized分段锁优化、LinkedHashMap的accessOrder机制如何支撑LRU缓存实现,以及CopyOnWriteArrayList在迭代期间写操作的快照隔离原理。第四,**Spring框架**相关题目覆盖IoC容器生命周期(BeanDefinition注册→BeanFactoryPostProcessor→InstantiationAwareBeanPostProcessor→InitializingBean→DisposableBean)、AOP动态代理选型逻辑(JDK Proxy vs CGLIB的classloaderfinal限制)、事务传播行为(PROPAGATION_REQUIRES_NEW为何会挂起旧事务并新建TransactionInfo)、Spring Boot自动配置原理(@EnableAutoConfiguration→spring.factories→Condition条件装配)、以及Spring Cloud Alibaba Nacos注册中心的心跳续约、健康检查临时/持久实例模型差异。第五,**IONIO体系**强调BIO阻塞模型的线程资源瓶颈、NIO多路复用Selector的epoll/kqueue底层封装、Buffer的position/limit/capacity状态机流转、Channel的scatter/gather操作、FileChannel的MappedByteBuffer零拷贝映射,以及Netty的Reactor线程模型(BossGroup/Accept线程WorkerGroup/IO线程分离)、ByteBuf内存池化管理PooledDirectByteBuf的引用计数回收机制。第六,**反射动态代理**部分需理解Class对象的三种获取方式(Class.forName vs ClassLoader.loadClass的初始化差异)、Method.invoke的JIT内联优化限制、反射调用性能损耗根源(取消访问检查的SecurityManager开销、参数类型校验成本),以及Proxy.newProxyInstance生成字节码的动态类命名规则InvocationHandler回调执行链。第七,**GC调优实战**涵盖不同垃圾收集器适用场景(G1适合4GB~64GB堆且停顿可控,ZGC面向TB级堆10ms级STW)、GC日志字段解读([GC (Allocation Failure)、[G1 Evacuation Pause]、[G1 Mixed GC])、Metaspace内存泄漏排查(ClassLoader未释放导致Klass Metaspace持续增长)、以及FinalReference队列积压引发的Full GC连锁反应。第八,**综合工程能力**隐含在题目背后如如何用ThreadLocal避免 SimpleDateFormat线程安全问题却引发内存泄漏(弱引用KeyEntry清理时机)、如何通过Unsafe类实现无锁队列、如何利用Java Agent + Instrumentation实现方法耗时监控、以及Spring事务失效的七大典型场景(this调用、异步线程、非public方法、异常被捕获、rollbackFor配置错误、数据库引擎不支持事务、代理对象未被Spring管理)。整套208实为一面技术棱镜,折射出Java工程师对语言本质、框架设计哲学、操作系统交互、硬件特性适配及大规模系统稳定性保障的立体认知深度,是检验是否具备从CRUD开发者蜕变为架构师的关键标尺。
Java OOM问题全解析[项目源码]
Java OOM问题全解析的详细内容涉及对Java服务中遇到的内存溢出问题进行深入探讨,文章开篇即对OOM的含义进行了解释,涵盖了Java堆内存溢出、元空间溢出、直接内存溢出和虚拟机栈溢出等多种类型,并对它们的技术特征进行了细致分析
1
AI时代Java面试进阶:场景题并发、JVMSpring原理深度解析
LKEG
Java面试场景题实战:并发扣库存OOM排查
本文聚焦Java面试中日益重要的场景题,涵盖并发扣库存、订单超时关闭、接口幂等性、MQTT设备接入及OOM排查五大高频实战场景。强调从工程判断力出发,结合业务约束比较方案优劣,辅以可运行代码兜底设计。内容包含刷闭环方法、面试追问应对框架、典型环境坑排查(如Lombok兼容性、JDK版本配置、非堆内存OOM),并突出Redis Lua、ZSET、唯一索引、MQTT QoS等关键技术落地细节。
weixin_34364071
386
Java面试场景题实战:并发扣库存、慢查询缓存优化全解析
本文系统解析Java面试中五大核心场景题:并发扣库存防超卖(数据库条件更新+Redis预扣减)、MySQL慢查询排查与索引优化(EXPLAIN分析、索引失效规避、深分页优化)、Redis三大问题应对(穿透/击穿/雪崩的布隆过滤器、互斥锁、过期时间分散)、消息队列最终一致性保障(Kafka消息不丢失幂等消费)、JVM OOM线上排查(堆dump分析、内存泄漏定位)。内容聚焦真实工程落地,涵盖技术选型依据、代码/SQL关键实现、边界处理及监控方案。
weixin_34074740
285
2025年Java秋招面试必看最新场景题+八股文全解析
本文聚焦2025年Java秋招面试,涵盖核心八股文,如HashMapConcurrentHashMap区别等;高并发与分布式场景题,像秒杀系统超卖问题解决办法;数据库缓存优化,包括MySQL索引失效情况等。还提及云原生、大模型辅助编程等新趋势及面试技巧。
小凡敲代码
802
Java面试场景题解析:从八股到项目实战,覆盖并发缓存分布式
本文聚焦Java面试高频场景题,覆盖缓存穿透/击穿/雪崩、接口幂等性、Redis/Zookeeper分布式锁、MQTT车牌识别对接、消息队列削峰、Spring事务失效及高并发内存溢出排查等核心问题。强调从真实项目出发,结合调用链分析、技术选型对比、失败兜底设计代码落地能力,提升面试中方案设计、取舍判断工程表达水平。
weixin_34199405
481
Java全栈工程师实战面试方案设计指南
本文系统阐述面向Java全栈工程师的结构化面试方案,涵盖能力模型构建、场景化题目设计原则及核心考察模块JVM内存泄漏与并发ID生成、Spring Boot自动配置冲突解决、微服务拆分Saga事务、分布式故障排查、Dockerfile优化、CI/CD流水线设计、Service Mesh集成及云原生改造等。强调白板编码、系统渐进设计反模式识别,提供可落地的评分红线与面试官避坑方法。
bit小兵
2633
Java面试30天速成高频考点、场景题与实战策略全解析
本文聚焦Java面试核心模块,包括集合(HashMap原理线程安全)、并发编程(JMM、线程池7大参数、AQSJUC组件)、JVM(内存结构、GC机制、CMS/G1对比、类加载调优)、MySQL(B+树索引、事务隔离级别、MVCC、行锁/间隙锁)、Spring(IoC/AOP原理、Bean生命周期、事务传播与失效场景)及典型场景题(性能排查、秒杀设计、缓存问题)。强调高频考点、结构化答题框架知识串联策略,适用于短期突击。
weixin_30562507
314
2025京东后端面试指南:并发、JVM、MySQLRedis全解析
本文系统梳理2025年京东Java后端面试四大核心模块:Java并发(synchronized、Lock、线程池、volatile、AQS)、JVM(内存模型、GC、OOM排查)、MySQL(索引失效、MVCC、间隙锁、事务隔离)、Redis(缓存穿透/击穿/雪崩)。结合电商真实场景库存扣减、订单超时、分布式锁续期)深入原理实操,强调原理推演、故障排查和项目量化表达,拒绝纯八股背诵。
aofan9566
283
Java面试攻略从八股文到场景题实战转型
本文聚焦当前Java面试从八股文背诵向真实场景问题解决能力的深刻转变,系统梳理JVM内存模型与OOM排查并发编程底层机制(AQS/CAS)、MySQL事务隔离Redis缓存方案、Spring核心原理及自动配置、高并发系统设计(如秒杀)线上故障排查(CPU飙升/内存泄漏)等关键技术点,并融入AI辅助编程、智能化运维等新要求,强调技术深度、系统思维综合能力并重。
weixin_30411819
389
2025年Java面试终极指南高频八股文与场景题全解析
本文涵盖Java面试多方面核心考点。包括Java基础的HashMap、并发编程,JVM的内存模型GC算法、OOM排查,数据库的MySQL索引优化、Redis高可用方案,分布式系统的秒杀架构与事务解决,微服务的Spring Cloud Alibaba生态、Service Mesh实践,以及Java 21新特性等内容。
小凡敲代码
888
Java后端面试7天冲刺计划核心知识点高频场景题全解析
本文系统梳理Java后端面试高频考点,涵盖Java基础、并发编程(JUC)、JVM原理、MySQL数据库、Spring框架、场景题与系统设计六大模块,按7天递进式学习路径组织,强调知识结构化、原理理解与实战编码验证,聚焦线程安全、GC机制、索引优化、事务传播、缓存设计等关键技术点,助力求职者高效备战技术面试
weixin_30613433
417
Java全栈开发面试深度解析与实战指南
本文系统梳理Java全栈开发面试的四大能力层级:Java核心原理(含HashMap底层结构、扰动函数、线程安全)、JVM调优(OOM排查四步法、类加载机制);Spring循环依赖三级缓存机制、MyBatis缓存失效场景;Redis分布式锁演进(基础版/Lua/Redlock)、分布式事务方案对比;以及性能优化(秒杀三级策略)和线上问题排查(CPU/SQL/网络)。强调深度理解与实战应答方法。
weixin_30363509
444
2026年Java面试场景题解析:从系统设计到AI集成的实战指南
本文系统解析2026年Java中高级岗位核心面试场景题,涵盖秒杀系统设计、深分页优化、JVM OOM与CPU飙高排查、慢SQL与事务锁优化、分布式事务(Seata)、服务熔断(Resilience4j)、电商库存与订单状态机,以及Spring AI集成和智能推荐等AI融合实践。重点突出性能调优、高并发架构、故障定位方法论及STAR/4S等系统设计思维。
weixin_33724059
430
Java后端面试100问核心考点项目场景题全解析
本文系统梳理Java后端面试七大核心模块:Java基础(String、equals/hashCode、泛型、反射、异常)、集合框架(HashMap底层、put流程、ConcurrentHashMap线程安全机制)、并发编程(synchronized/ReentrantLock、volatile、线程池参数、ThreadLocal内存泄漏)、JVM(内存区域、GC算法、OOM排查)、Spring/Spring Boot(IOC/AOP、Bean生命周期、事务失效场景、自动配置原理)、MySQL(索引失效事务隔离、聚簇索引、慢SQL优化)、Redis(缓存三击、一致性方案、分布式锁、持久化策略),并融合项目场景题答题模板一周冲刺计划,强调从八股文到工程实践的转化。
weixin_30367169
506
Java后端面试7天冲刺核心考点高频场景题全解析
本文系统梳理Java后端面试7天冲刺计划,覆盖Java基础(面向对象、集合、异常)、并发编程(线程状态、锁机制、JUC组件)、JVM(内存模型、GC算法、类加载)、MySQL(索引B+Tree、事务ACID、SQL优化)及Spring(IoC/AOP/事务)五大核心技术模块,并结合高频场景题(秒杀、CPU飙升、缓存三崩)强化实战能力。
weixin_30414305
367
Java全栈开发面试核心要点与实战解析
本文系统梳理Java全栈开发面试关键内容,涵盖Java核心基础(JVM内存模型、并发三要素、HashMap树化原理)、数据库ORM(索引失效场景、MyBatis缓存陷阱)、栈技术链(Vue3、微前端、前后端认证接口规范)、微服务架构(Spring Cloud Alibaba、Nacos选型、分布式事务、秒杀设计)、JVM调优(OOM排查、GC日志分析)及Redis高级应用(缓存穿透、热key处理)。强调系统设计能力与实战表达方法,聚焦现代技术栈演进与面试应对策略。
weixin_34194087
465
Java大厂面试核心JVM、并发与Spring生态解析
本文聚焦Java大厂面试的三大核心技术板块JVM原理性能优化(含内存模型、GC调优、OOM排查)、并发编程(volatile、CAS、锁升级、ThreadLocal、AQS)、Spring生态(IoC三级缓存、Bean生命周期、事务传播机制及失效场景)。同时涵盖分布式事务(Seata AT模式、CAP权衡)和系统设计方法论,强调源码理解生产问题解决能力。
weixin_34037515
361
一线大厂 Java面试:笔试 + 面试高频(含答案解析
本文涵盖一线大厂Java岗位笔试与面试高频题目,包括Java基础、JVM、并发编程核心知识点及HashMap原理、Spring事务失效、MySQL分库分表等深度场景题,提供详细答案解析与排查思路,帮助开发者系统掌握核心技术要点。
卡卡酷卡BUG
1209
2025小米Java面经全解析:从基础八股到JVM调优与并发实战
本文系统梳理2025年小米Java岗位面试逻辑,聚焦Java基础原理、并发编程(volatile/synchronized/ReentrantLock)、JVM调优(OOM排查、内存结构、GC机制)、Spring Boot核心(Bean生命周期、循环依赖、事务失效)、中间件应用(Redis缓存策略、Kafka消息可靠性)及手撕代码规范。强调从业务场景出发理解技术点,如IoT设备上报中的并发设计、本地缓存引发的OOM真实复盘等,突出实战能力原理深度结合。
weixin_30367169
1073
Java面试转型从八股文到场景实战的系统性应对策略
本文系统梳理Java面试从传统八股文向真实场景题的转变趋势,聚焦Java基础、JUC并发、JVM调优、MySQL优化及Spring事务等核心技术模块,强调原理深度、知识串联结构化解题思路。重点解析ConcurrentHashMap源码演进、线程池参数设计、JVM内存泄漏排查、B+树索引优化、Spring事务失效场景及秒杀等典型场景题的分层拆解方法,突出工程实践能力故障定位逻辑。
weixin_34189116
316
Java全栈工程师面试核心要点与实战技巧
本文系统梳理Java全栈工程师面试五大核心环节:Java基础(JVM内存模型、并发三要素)、Spring原理(IoC启动流程、事务失效场景)、实战(前端工程化、数据库执行计划优化)、系统设计方法论(四步法)及故障排查(Arthas、SkyWalking)。强调技术深度项目落地能力并重,涵盖应答策略(STAR法则)避坑指南。
weixin_34111790
444