【面经】上海某小厂 Java 后端开发一面
求职岗位:Java 后端开发工程师(校招 / 实习)
面试形式:腾讯会议(开启摄像头,1 对 1)
面试时长:27 分钟
一、自我介绍与项目深挖(约 7 分钟)
- 自我介绍
- 常规开场白:学校专业、技术栈主修(Java、Spring Boot、MySQL、Redis、微服务),列举了两个主要项目:民宿社区 与 智能客服系统。
- 智能客服(RAG 大模型项目)深挖:你遇到过最深刻的 Bug 是什么?
- 我的回答:
- 提到了智能客服在推荐衣服尺码时频繁偏小的 Bug。
- 排查根因:知识库在进行文本分块(Chunking)时,采用了固定的 500 字机械切分规则,直接切断了 Markdown 表格的结构完整性,导致后半段切片丢失了表头。大模型做向量检索匹配到后半段切片时缺乏表头上下文,进而产生幻觉,推荐了错误尺码。
- 解决方案:重构切分逻辑,在解析表格等结构化数据时进行语义切片,并强制为后续每个子分片拼接注入原表格表头元数据,补全上下文。
- 面试官反馈:对这个真实踩坑案例表示认可,追问了后续落地细节。
- 观点探讨:AI 辅助开发是否降低了对开发者基础能力的要求?
- 我的回答:
- 明确反驳了这个观点。指出 AI 代码生成工具往往会产出冗余代码甚至潜藏逻辑漏洞,AI 本质只是提效工具;如果开发者自身缺乏扎实的底层功底和架构思维,不仅无法驾驭 AI,更无法对 AI 产出的错误逻辑进行有效鉴别与纠偏。
二、操作系统与 Java 并发(约 5 分钟)
- 进程与线程的区别?
- 我的回答:
- 进程是操作系统资源分配的基本单位,拥有独立的虚拟地址空间和内存资源;
- 线程是 CPU 调度执行的基本单位,属于进程内部,多个线程共享该进程的堆、方法区和代码段,但每个线程拥有独立的程序计数器(PC)和虚拟机栈。
- 追问:多线程上下文切换(Context Switch)的定义与底层本质?
- 考场翻车:当时紧张,顺口解释成了“线程间的数据透传与共享”。
- 避坑复盘:
- 切记不是传数据!上下文切换是 CPU 从一个线程切换到另一个线程时的状态保存与恢复机制;
- 核心是将旧线程的 CPU 寄存器状态和程序计数器(PC 指针)存入内存的 TCB(线程控制块),再从内存加载新线程的上下文到 CPU 寄存器中;频繁切换会严重浪费 CPU 算力并导致 CPU Cache 失效。
- 阻塞队列(BlockingQueue)及其应用场景?
- 我的回答:当时卡壳,坦言该知识点暂未深入接触。
- 避坑复盘:
- 核心特性:队列满时放元素自动阻塞,队列空时取元素自动挂起,天然支持生产者-消费者模型;
- 最经典场景:Java 线程池(ThreadPoolExecutor)的任务排队缓冲区(workQueue);
- 经典实现:ArrayBlockingQueue(数组单锁)vs LinkedBlockingQueue(链表双锁读写分离,默认无界易 OOM)。
三、Redis 缓存与中间件(约 4 分钟)
- Redis 常见数据类型及核心业务场景?
- 我的回答:
- 列举了 String、Hash、List、Set、ZSet 以及用于地理位置的 Geo 结构;
- 重点阐述了在业务中利用 String/Hash 做热点数据缓存,以及利用 SETNX / Redisson 实现分布式锁的底层逻辑。
- Redis 主从同步是如何工作的?
- 我的回答:
- 答出了主节点(Master)负责写、从节点(Slave)负责读的主从拓扑架构。
- 避坑复盘:
- 首次连接执行全量同步(Master bgsave 导 RDB 发送给 Slave,期间新写入通过 replication buffer 补发);
- 之后正常状态执行增量命令传播;
- 网络抖动短时断开重连,依靠 Master 内存里的环形积压缓冲区(repl_backlog_buffer)按 offset 增量续传,避免重复导出全量 RDB。
四、MySQL 数据库原理(约 4 分钟)
- 生产中分库分表的场景与分片键(Sharding Key)选择?
- 我的回答:
- 结合单表数据量千万级、查询性能下降的背景阐述了水平拆分策略;
- 针对分片键选择,回答了通常基于用户 ID(user_id)进行哈希取模运算,使数据均匀路由落库。
- 为什么 MySQL 的表必须建主键?
- 我的回答:
- 业务上提供唯一性约束;
- 底层架构上,InnoDB 存储引擎是索引组织表,必须依赖主键构建聚簇索引(B+ 树);如果不指定主键,InnoDB 会自动寻找第一个非空唯一索引,若还没有则会隐式生成一个 6 字节的 row_id,反而不利于性能与查询优化。
五、极限海量数据压测场景题(约 4 分钟,极限摸底连环炮)
- 【高难场景】20 亿 QQ 号,如何快速去重?
- 考场翻车:
- 没听清误听成了 21 个,脱口而出用 Java Set 集合;
- 面试官反问:“20 亿个数据放内存,Set 会怎样?”——我才意识到是 20 亿,Set 肯定直接 OOM 爆内存;随后我提出分批+多线程,面试官驳回表示处理耗时太长,缺乏大数据思维。
- 避坑复盘(满分标准解法):
- 降维打击:位图(Bitmap)!
- QQ 号是纯整数数字(无符号整型最大约 43 亿),一个数字对应 1 个 bit 位(0 不存在,1 存在);
- 覆盖 43 亿 QQ 号的全量位图只需要:43 亿 bits ÷ 8 ÷ 1024 ÷ 1024 ≈ 512 MB 内存!
- 单台普通机器仅需 512MB 内存即可在几秒内完成 20 亿数据去重,既快又彻底杜绝 OOM。
- 【高难场景】千万级 Excel 数据如何极速解析并入库?
- 考场翻车:被连环追问后节奏有点乱,思考后选择跳过,随后补充了部分解析入库逻辑。
- 避坑复盘(工业级标准解法):
- 解析防 OOM:严禁原生 Apache POI 一次性全加载到堆内存,改用 EasyExcel(基于 SAX 逐行流式解析),内存恒定仅十几兆;
- 入库防网络卡死:设置监听器每满 3000 条打包成一个批次,交由线程池并发调用 JDBC 批量插入(batchUpdate),同时配置参数 rewriteBatchedStatements=true 重写 SQL。
六、Linux 生产实战排错(约 3 分钟,全场高光挽回局面)
- 线上服务器突然运行极其缓慢、CPU 飙高到 100%,你的标准排查链路是什么?
- 我的回答(答得很顺):
- 终端执行 top 命令,按 CPU 排序快速定位高占用的 Java 进程 PID;
- 执行 top -Hp 命令,展开查看该进程内部各个线程的 CPU 占用,锁定罪魁祸首线程 TID;
- 指出需要将该线程 ID 转换为 16 进制(即 printf "%x\n" );
- 执行 jstack | grep -A 20 <0x_tid>,精准抓出该线程当前卡死在哪一行 Java 业务代码上(死循环还是锁竞争);
- (加分项)提到生产环境可使用阿里开源的 Arthas 工具,执行 thread -n 3 一键秒级定位最占 CPU 的前 3 个线程堆栈!
- 面试官反馈:面试官对此条排查链路点头表示认可。
参考来源:https://www.nowcoder.com/feed/main/detail/299bc56dbdd24f009cd2b91cf77ab8d8
公众号进入网站体验更佳

