面灵AI→

美团后端开发岗面经合集:JVM 锁、系统调用与 Redis 淘汰策略

轮次
多轮面试合集
时间
2026-10
来源
牛客网

《面试题目》

面经 01

  1. 为什么你这个专业要找互联网工作?
  2. CSS 匹配缓存怎么设计?
  3. 什么是 Copy-On-Write 操作?
  4. AI 项目高并发怎么做?
  5. 线程池设计需要注意什么?
  6. 什么时候用锁?什么时候不用?
  7. 原子变量是什么?
  8. 数据库表结构怎么设计?
  9. 如何保证消息顺序?
  10. 数据量大怎么办?
  11. 索引什么时候会失效?
  12. 为什么用 MQ?
  13. 如何保证消息不丢?
  14. MVCC 原理?
  15. 是否接受写 Java?

面经 02

  1. 实习期间你具体做了什么?数据从哪里产生,主要分析什么?
  2. 你们部门是开发数据分析 agent 这个数据产品,还是数据部门自己去挖掘数据?
  3. 这个数据产品具体有哪些功能?
  4. 它实际上是怎么做的?是不是做了能力适配,让业务团队直接使用大模型?
  5. 内置的 MCP 做了哪些工作,让数据分析 agent 表现更好?你在设计过程中参与了哪些具体事项?
  6. 在意图识别这块,你具体做了什么?
  7. 进入意图识别之后,针对深度分析等场景是怎么适配的?主要是装配 Skill 和 MCP 吗?
  8. 除了 Skill、MCP 和思考强度限制,还有哪些方式能让模型在特定场景下表现更好?
  9. 生产环境那个实例挂掉,是通过数据分析 agent 做的吗?你是怎么分析 dump 文件的?
  10. 这个数据产品是不是有页面,不同业务线用户可以上传文件、数据或文档做分析?底层是怎么实现的?
  11. 招聘助手按渠道适配、消息路由,最终产品形态是什么?是浏览器插件还是别的?
  12. 是本地起服务、本地起页面吗?不同渠道是否需要打通实际招聘平台?
  13. 你说的渠道具体指什么?
  14. 岗位这些数据从哪里来?
  15. 这个助手的作用是什么?是从招聘平台获取信息后,在本地页面按渠道分发到社交平台吗?
  16. 它怎么帮用户找到合适岗位?需要爬取吗?有爬虫吗?
  17. 具体涉及哪些外部招聘平台?是爬虫还是用户登录?登录和反爬怎么解决?
  18. 你平时用得比较多的 AI 编程工具或模型是什么?实际体验如何?
  19. 你怎么理解 Prompt Engineering 和 Context Engineering?
  20. 你了解现在主流的 Agent 架构吗?
  21. ReAct 为什么不适合大型复杂项目?
  22. 融合架构整体采用 Plan,如果初始 Plan 就错了,或者中间步骤确认后发现问题,怎么办?
  23. Java 中 List 里放自定义对象,怎么排序?
  24. 自定义对象如何实现排序?
  25. Lambda 表达式背后的接口是什么?
  26. synchronized 修饰静态方法和实例方法有什么区别?锁对象分别是谁?类作为锁对象时有对应实例吗?
  27. 加锁之后锁标记放在哪里?怎么保证互斥?
  28. synchronized 修饰实例方法后,标记该实例已被当前线程持有,这个标记信息存在哪里?
  29. Java 多态中,父类引用指向子类实例,实际执行子类行为,动态绑定具体是怎么实现的?
  30. Java 线程池里 execute 提交任务和 submit 提交任务有什么区别?
  31. volatile 的实现原理,你知道哪些层次都可以说说。
  32. volatile 的这些功能,在 JVM 和操作系统层面分别怎么支持?
  33. 策略模式和模板方法模式有什么区别?
  34. 如果进程申请的内存远超过物理内存,操作系统怎么处理?
  35. 发生系统调用时,比如读文件,操作系统会经过什么流程?
  36. 内核处理系统调用时,进入和返回后,和应用程序怎么交互?
  37. 系统调用通常带参数,比如 read,内核怎么知道读哪个文件?返回后怎么回到应用程序下一行继续执行?
  38. 保存上下文的表具体在哪里?存在哪?
  39. TCP 第四次挥手时,第四个数据包丢失会怎么样?
  40. 是重发第三次挥手吗?
  41. 如何用 UDP 实现 TCP 的可靠传输?
  42. MySQL/InnoDB 的日志主要有哪些?各自作用是什么?
  43. 一个事务提交时,redo log、undo log、binlog 的落盘顺序是什么?
  44. Redis 的淘汰策略你了解吗?
  45. LRU 和 LFU 各有什么不足?
  46. 怎么优化 LFU?Redis 里 LFU 是怎么实现的?会不会增加开销?
  47. 怎么保证 LFU 的计数准确?
  48. 手撕:盛最多水的容器。

面经 03

  1. 项目几个人开发、多少 PD、多大体量?只有一个后端吗?
  2. 埋点上报最终数据存到哪?埋点平台底层怎么存储?会丢吗?
  3. 上报这个数据合理吗?采集的都是什么数据?为什么这种数据要存到服务端?
  4. 有没有开发时才发现不该由你们来开发的例子?没有技术方案吗?
  5. 上线之后有没有问题?线上 bug 之类?
  6. 这个工作流是谁派发的任务,还是你自己想做的?是导师提的你来承接吧?
  7. 任务是先执行再检查再继续,全自动的过程,那第一个任务代码就有问题,会把错误放大,出现过吗?怎么解决的?是逻辑问题还是别的?
  8. 同事用后给过什么反馈?生成的代码符合团队代码规范吗?没考虑过加规则约束吗?分析过原因吗?
  9. 用 AI 这么久,模型生成代码质量不高有哪些原因?任务给多了注意力转移你发现过吗?
  10. 你们主要用 Codex,是吧?没用 Claude Code?
  11. 你做的东西调研过业界吗?
  12. AI 返回的结果业务能直接看懂吗,还是需要技术人员再转换话术?有没有考虑继续迭代?
  13. MySQL 事务的隔离级别有哪些?
  14. MySQL 优化做过吗?慢查询如何处理?
  15. Java 线程池的执行流程是什么?从添加任务到拒绝策略如何处理?
  16. 线程的创建过程是什么?
  17. MQ 的主要使用场景是什么?开发消费者有哪些原则?幂等如何实现?
  18. Redis 如何保证原子性?如何实现只消费一条?为什么用 Lua 脚本而不用 SETNX?
  19. Spring 事务有哪些实现方式?代码如何编写?

面经 04(原帖在此处被截断)

  1. 面试官开始提问(原帖截断)

《参考解析》

1. Copy-On-Write 与缓存设计。 COW 的核心是「读共享、写复制」:多个读者共享同一份数据,写者先复制一份再改,改完原子替换指针,读者要么看到旧版本要么看到新版本,不会读到半成品。Java 的 CopyOnWriteArrayList 就是每次写都复制整个数组,适合读多写少、数据量小的场景(比如监听器列表),写多时会频繁复制、内存抖动。Redis 的 BGSAVE 也是 COW:fork 出子进程共享页表,父进程写时复制页面。浏览器里的「CSS 匹配缓存」是另一个层面的缓存——把选择器匹配结果按元素/规则缓存,DOM 变化时按失效范围清理,设计要点是缓存的 key(元素 + 规则集 + 状态伪类)、失效粒度(避免一个 class 变化就全量失效)、以及内存上限。

2. 线程池、锁与原子变量。 线程池设计关注:核心/最大线程数、有界队列、拒绝策略、线程命名(便于排查)、异常处理、以及池的隔离(不同业务不共用)。用锁的判断是「有没有共享可变状态、临界区是否真的需要互斥」:无状态服务、局部变量、不可变对象都不需要锁;能用原子变量/CAS 解决的单变量计数不要用锁;读多写少可以用读写锁或 COW;跨进程才考虑分布式锁。原子变量(AtomicInteger、LongAdder)靠 CPU 的 CAS 指令保证单变量原子性,LongAdder 在高并发下用分段累加降低竞争,最后求和。

3. 消息顺序、可靠性与表设计。 保证顺序的三要素:同一业务键路由到同一分区/队列(Kafka 用 key 做 partition,RocketMQ 用顺序队列)、单分区内单消费者串行消费、消费失败不要跳过(否则顺序断裂)。不丢消息要三段都做:生产端确认(acks=all + 重试)、Broker 持久化与副本(min.insync.replicas)、消费端手动提交 offset(处理成功再提交)。表设计先定访问模式:主键选择、避免大宽表、冷热字段分离、必要的冗余(减少 join)、以及分库分表的 shard key;数据量大时先看能不能归档/分区,再考虑分片。索引失效的典型场景:对列做函数/运算、隐式类型转换、like '%x' 前导通配、联合索引不满足最左前缀、or 两边有一边没索引、以及优化器判断全表扫更便宜。

4. MVCC。 InnoDB 给每行加隐藏的 DB_TRX_ID(最后修改的事务 id)和 DB_ROLL_PTR(指向 undo log 的版本链)。快照读时,事务拿着自己的 read view(活跃事务 id 列表、最小/最大事务 id),沿版本链找「对当前事务可见」的版本:已提交且早于快照的可见,未提交或晚于快照的不可见,继续沿 undo 找。RC 每次查询生成新 read view,RR 在第一次查询时生成并复用,所以 RR 能避免不可重复读;幻读靠间隙锁(当前读)或快照读的版本可见性来规避。MVCC 只作用于快照读,select ... for update、update、delete 走当前读并加锁。

5. synchronized、动态绑定与 volatile。 synchronized 修饰实例方法锁的是 this 对象,修饰静态方法锁的是 Class 对象(类只有一个,所以是全局锁),修饰代码块锁的是括号里的对象。锁信息存在对象头的 Mark Word 里:偏向锁记录线程 id,轻量级锁记录指向栈上 Lock Record 的指针,重量级锁指向 monitor;JVM 通过 CAS 修改 Mark Word 来抢锁,失败则膨胀升级。多态的动态绑定靠虚方法表(vtable):每个类有一张方法表,对象头里的类型指针指向类元数据,调用虚方法时按运行时类型查表,找到子类重写后的入口。volatile 保证可见性和有序性:JVM 层插入内存屏障,硬件层靠缓存一致性协议(MESI)让其他核的缓存行失效,写操作直接写回主存。execute 提交 Runnable 且不返回结果、异常会直接抛给线程池的未捕获异常处理器;submit 提交 Callable 返回 Future,异常被封装在 Future 里,不 get 就看不到。

6. 内存、系统调用与 TCP。 进程申请的内存超过物理内存时,操作系统用虚拟内存 + 按需分页:先只分配虚拟地址空间,访问时缺页中断再加载;物理内存不够就把不活跃页换出到 swap(或直接 OOM kill)。系统调用流程:用户态把系统调用号放进寄存器、执行 syscall 指令陷入内核 → 内核保存用户态上下文(寄存器、栈指针、返回地址)到内核栈 → 按调用号查系统调用表执行 → 参数通过寄存器/用户态指针传入,内核用 copy_from_user 校验并拷贝(read 的 fd 用来查进程的文件描述符表)→ 返回时恢复上下文、把返回值放回寄存器、切回用户态继续执行下一条指令。上下文保存在内核栈和 task_struct 的 thread_struct 里(x86 保存 rsp/rip/rflags 等)。TCP 第四次挥手(客户端最后的 ACK)丢失时,服务端停在 LAST_ACK 并超时重传第三次挥手(FIN+ACK);客户端已经进入 TIME_WAIT,收到重传的 FIN 会再回一个 ACK,所以不会卡死,只是服务端晚一点关闭。

7. InnoDB 日志与落盘顺序。 redo log 是物理逻辑日志,记录页的修改,保证崩溃恢复(WAL);undo log 记录旧版本,用于回滚和 MVCC;binlog 是 server 层的逻辑日志,记录语句/行变更,用于主从复制和归档。提交顺序:先写 redo(prepare 状态)→ 写 binlog → redo 标记 commit,即两阶段提交(2PC),保证 crash 后 redo 与 binlog 一致;组提交(group commit)把多个事务的 fsync 合并以降低开销。

8. Redis 淘汰与 LFU。 淘汰策略八种:noeviction(写满报错)、allkeys-lru、allkeys-lfu、allkeys-random、volatile-lru、volatile-lfu、volatile-random、volatile-ttl。LRU 的不足是「偶发一次全量扫描会把冷数据顶成热数据」(缓存污染);LFU 按访问频率淘汰,能抵抗偶发访问,但老数据的计数会一直累积、新数据难以出头。Redis 的 LFU 用 8 bit 存计数(概率递增,到 255 饱和)加 16 bit 存「上次衰减时间」,按 lfu-log-factor 控制增长难度、lfu-decay-time 控制衰减,避免计数无限累积。它不增加额外内存(复用 LRU 字段),但计数是近似值(概率递增 + 定时衰减),所以「准确」只能做到趋势正确;需要精确计数就得自己维护哈希表,代价是内存和复杂度。

9. 手撕:盛最多水的容器。 双指针从两端向中间收:面积 = min(h[l], h[r]) * (r - l),每次移动较矮的一侧(因为移动高的一侧不可能让面积变大),O(n) 时间、O(1) 空间。要能解释为什么移动矮的一侧不会漏掉最优解:矮边是当前面积的瓶颈,固定它、换更高的边只会让宽度变小,所以以它为一边的最优解已经枚举过了。

10. 工程与 AI 协作。 埋点数据一般走「客户端上报 → 网关/日志服务 → Kafka → 数仓(Hive/Iceberg)」,底层是列式存储 + 分区,丢失靠客户端本地缓存重发和服务端幂等去重。AI 生成代码质量不高的常见原因:上下文不足(没给足相关文件和规范)、任务粒度过大(一次改太多处,注意力分散)、缺少验证(没有测试/编译反馈)、以及模型对项目约定不熟。改进靠「小步任务 + 明确验收 + 工具反馈闭环」:每次只让它改一处、改完跑测试和 lint、失败把错误信息回灌;规范用 lint/模板固化,而不是只写在提示词里。