2026/10/12 7:48:54

Java面试进阶:从背概念到讲清分布式、高并发与数据库原理

Java面试进阶:从背概念到讲清分布式、高并发与数据库原理 每年三月前后我的私信就会进入一年中最热闹的时段。各种金三银四Java面试的求助刷屏有在背分布式锁的、有在刷MySQL索引的、有在临时抱佛脚补设计模式的。问题高度一致——到底要准备到什么程度才不会被挂我做了多年开发也当过技术面试官很清楚一个事实大部分候选人不是不会而是把分布式、中间件、高并发、数据库、设计模式、算法这六个方向学成了孤岛每个名词都能说两句但串不成一条解决问题的链路。这篇参考指南不会给你堆一份面经大全而是想用一套相对完整的复习框架把这六个方向按面试官的实际追问方式重新捋一遍。适用对象很明确准备社招或跳槽的Java工程师尤其是工作两三年、第一次认真准备大厂面试的同学。你可以把它当成冲刺前的索引也可以当成检验自己知识深度的清单。最重要的是它能帮你从背过变成讲得清这才是面试真正考察的东西。1. 金三银四的真实战场面试官到底在问什么1.1 为什么面经背了一百遍还是挂有个现象我印象很深。有一年面试一位候选人简历上写着熟悉Redis我问他Redis为什么快他秒答基于内存。我再追问既然基于内存那你的缓存数据万一丢了一部分业务怎么兜底他愣了一下开始背持久化RDB和AOF的区别。等我又问如果AOF文件越来越大重写期间还能不能继续写他彻底接不上话了。这不是个例。它说明一个核心问题背答案和真正理解之间隔着一整条为什么的链路。面经给的是结论面试官问的是推导过程。比如Redis快这个结论背后涉及内存访问、IO多路复用、单线程模型避免竞争、数据结构设计四个层面每个层面又能继续向下追问。你只背第一层第二层必然露馅。所以准备面试第一件事是调整心态。别把面经当题库把它当一个大纲。看到任何一道题先问自己三个问题这个知识点解决什么问题它跟相邻知识点是什么关系如果系统运行中它出了问题我如何排查和恢复这三个问题答得上来面试官基本拦不住你。1.2 面试官判断人的四个维度我自己的面试习惯是不预设候选人必须答出所谓标准答案而是从四个维度打分。第一是基础扎实度。JVM内存模型、并发工具、集合类这些硬功夫是判断一个程序员下限的标尺。第二是方案设计能力。给你一个具体场景比如ERP库存扣减遇到高并发怎么办你能不能在十分钟内给出可以落地的链路而不是只会说加锁。第三是排查能力。线上CPU飙升、数据库连接池被打满你的排查步骤是什么。第四是表达逻辑。能不能把复杂概念拆成是什么、为什么、怎么做让对面的人听懂。这四条其实就是本篇后续章节的暗线。分布式事务、消息中间件、高并发设计、索引优化最后都会落到这四个维度上。你复习的时候也要有意识地拿四个维度去对照。2. 分布式与中间件从背概念到搭出链路2.1 分布式事务2PC、TCC、本地消息表到底怎么选分布式事务是Java面试里最容易让人背混的模块。两阶段提交是一种协议TCC是一种业务补偿方案本地消息表是一种最终一致性实践它们各自解决的问题不一样。面试官问分布式事务你了解哪些不是让你把名词罗列一遍而是想看你面对不一致场景时怎么取舍。我的建议是先用一个例子把问题串起来跨行转账A账户扣钱B账户加钱如果B加钱失败怎么办。这个场景下两阶段提交靠协调者统一所有参与者的提交决策但存在同步阻塞和协调者单点问题。TCC则把每个操作拆成Try、Confirm、Cancel三个阶段把预留资源和确认执行分离适合对一致性要求很高的业务但对代码侵入很大。本地消息表和事务消息走的是另一条路——主业务先把本地事务和消息写入同一个库再由消费者异步处理下游牺牲实时一致性换来系统解耦。答到这里最好再补一句现在很多实际落地会用Seata这种框架但框架只是把协议封装好了你依然要知道AT模式是基于全局锁和快照回滚实现的。面试官喜欢听到你对底层协议的判断比如2PC适合并发要求不高、强一致的内部系统对外的大型互联网业务更倾向于可靠消息TCC组合。这一句就能让答案上一个档次。2.2 分布式锁Redis锁和ZooKeeper锁只回答一半分布式锁几乎每次面试都会出现但多数人只会说Redis用setnx加锁ZooKeeper用临时顺序节点。这不是完整答案。面试官真正会接着问的是锁失效怎么办持有锁的节点GC停顿了怎么办锁的过期时间设多少合理Redis锁的核心写法是SET key value NX EX seconds注意这里必须保证原子性不能先setnx再expire。但这还不够因为如果业务执行时间超过锁过期时间锁会自动释放另一个线程就能同时进入临界区。Redisson的看门狗会帮你自动续期可如果你用的是裸Redis必须在业务代码里做主动续期或者在锁内校验业务时间。再说可靠性Redis主从切换时旧主上的锁还没来得及同步新主又没这个锁就可能导致重复加锁。这时候可以引入RedLock但RedLock本身也有争议不如直接说使用ZooKeeper可以保证强一致但性能比Redis低所以很多场景还是Redis配合续期以及对业务幂等做最后兜底。我在面试时听到最舒服的回答是候选人主动说锁不是万能的最终要保证数据正确还得靠业务幂等。这一句说明他真处理过线上问题。2.3 注册中心与配置中心Nacos、Eureka、Consul的高频差异中间件话题里服务注册与发现也是大热门。候选人通常知道Eureka是AP模型Consul是CP模型Nacos可以切换AP和CP。但面试官更关心的是你项目里的注册中心挂了服务之间还能不能调用为什么Nacos默认用AP而不是CP先解释机制服务A调用服务B如果A本地缓存了B的地址列表那么注册中心临时挂掉A依然可以靠缓存调用B。这正是Eureka和Nacos默认AP的原因——可用性优先允许短暂的服务列表不一致。Consul的CP则牺牲可用性保证一致性适合对服务发现准确性要求极高的内部系统。至于配置中心Nacos把配置变更推给客户端客户端通过长轮询感知变化所以Spring Cloud Config比起来更像拉模式实时性稍差。这里有个加分点可以顺便提一句配置中心推送配置后可以用RefreshScope刷新Bean但使用时要小心Bean重建带来的状态丢失这种经验细节比概念本身更值钱。3. 高并发场景不是背几个名词就能过关3.1 先搞清楚高并发的三个指标QPS、RT、可用性很多候选人一开口就是高并发用缓存、MQ、集群这种答案没有锚点。你连系统当前QPS是多少、响应时间目标是多少都没提方案就是空中楼阁。面试中可以先建立共识QPS是每秒请求数RT是平均响应时间二者相乘再乘以机器数量大概能估算系统容量。比如单机RT100ms一个线程一秒最多处理10个请求想要支撑1000QPS不算线程池放大效应至少需要上百个线程或几十台机器。有了这个数学模型再讨论技术选型就有逻辑了。缓存降低RT消息队列削峰填谷水平扩展提高QPS上限。面试官接着问你做过哪些优化时你就能拿出数据我们把首页接口从200ms优化到50ms后单机QPS从500涨到1200。更关键的是可用性也就是别人常说的高可用。99.9%和99.99%听起来只差一点点但一年不可用时间从8.76小时变成52分钟。你的系统依赖了多少中间件每个中间件有单点吗这些链路中任何一环挂了有没有降级方案这才是高并发设计的核心。3.2 缓存穿透、击穿、雪崩同一套思路怎么答这三个问题几乎是捆绑出现的。缓存穿透是查一个根本不存在的数据每次请求都打到数据库缓存击穿是热点KEY过期瞬间大量请求同时打到数据库缓存雪崩是大批KEY同时过期或Redis宕机数据库瞬间被压垮。我建议不要只背定义要背解决方案背后的思路。穿透的核心是如何让不存在的数据也能被缓存所以布隆过滤器拦截明显不存在的KEY或者把空值也缓存起来但空值要设置较短过期时间。击穿的核心是在KEY重建期间限制并发可以用互斥锁同一个KEY只允许一个线程去查库重建缓存其他线程等待也可以用逻辑过期后台异步更新但要注意旧数据在短暂时间内不一致。雪崩的做法更偏向错峰给过期时间加随机值同时做Redis集群避免单点。如果你能补一句布隆过滤器只能减少穿透不能完全消除所以数据库层面还是要做好防护面试官会觉得你考虑过工程权衡。3.3 限流、降级、熔断如何用Sentinel把链路保护起来高并发场景下保护系统不外乎这三板斧但很多人说不清限流和熔断的区别。限流是控制入口流量比如每秒只放行1000个请求熔断是当下游服务异常率超过阈值时快速失败不让调用方继续拖垮系统降级是主动放弃非核心功能比如电商大促时关闭评论展示力保下单流程。以Sentinel为例它的核心是资源抽象和规则配置。你可以给接口或方法定义资源再为资源设置QPS流控规则、线程数流控规则、熔断规则。实现原理上Sentinel会用责任链模式串起一系列Slot比如FlowSlot做流量控制DegradeSlot做熔断降级它内部用了滑动窗口计数器统计QPS和异常比例。有一个点容易被忽略服务A调用BB设置熔断阈值后A也要有响应超时时间和重试策略。熔断本质上是停止重试而不是反复把请求发过去。你在面试中能讲清楚当B恢复后Sentinel会进入半开状态放少量请求试探这就证明你真用过而不是只看过文档。4. 数据库深挖索引、事务与分库分表4.1 索引的常见追问回表、最左前缀、覆盖索引MySQL索引的面试题每年都是重灾区。候选人都会背B树主键索引叶子节点存整行数据二级索引叶子节点存主键值但碰到场景题就发懵。我给你整理一个高频追问链为什么用B树而不是B树因为B树数据都在叶子节点非叶子节点只存索引键树更矮更宽减少磁盘IO叶子节点有链表适合范围查询。什么是回表查询的列在二级索引里找不到还要回主键索引再查一次。覆盖索引能否避免回表比如联合索引(a,b,c)查询只返回a、b、c列那么直接在二级索引里取结果不需要回表。最左前缀是什么联合索引按定义字段顺序建B树查条件必须从最左字段开始跳过第一个字段索引就失效。面试时别只回答概念可以拿具体表举例CREATE INDEX idx_shop_status ON order(shop_id, status, create_time)如果查询条件是WHERE shop_id? AND create_time BETWEEN ? AND ?这个索引怎么走答案是可以走idx_shop_status的shop_id前缀但create_time无法走索引因为中间的status被跳过了。这种细节才容易让面试官点头。4.2 事务隔离级别与MVCC别只会背默认RRInnoDB默认隔离级别是可重复读这个谁都懂。关键问题在于可重复读怎么实现的这就得引到MVCC和锁上。MVCC的核心是隐藏字段和读视图。每行数据有DB_TRX_ID和DB_ROLL_PTR事务启动时创建ReadView记录当前活跃事务列表。快照读时通过版本链找到对当前事务可见的版本。可重复读和读已提交的差别在于读已提交每次SELECT都生成新的ReadView可重复读只在事务第一次SELECT生成ReadView所以能保证同一事务内多次快照读结果一致。但快照读解决不了幻读当前读SELECT ... FOR UPDATE要靠Next-Key Lock也就是记录锁加间隙锁。面试官最喜欢问在RR隔离级别下一个事务插入了一条其他事务新提交的数据为什么会被锁阻塞答案是插入意向锁与间隙锁冲突。答到这一步你还可以主动提一嘴很多人以为MVCC解决了幻读其实只解决了快照读的幻读当前读的幻读需要锁。这是面试中非常亮眼的辨析。4.3 分库分表ShardingSphere的主键与分布式ID问题分库分表是数据库模块的压轴题。候选人通常知道分库分表是为了解决单表数据量大、写入性能下降的问题但一落到分片键怎么选就卡壳。核心原则是尽量用查询频率最高的维度做分片键。比如订单表按user_id分片用户查询订单能直接定位到具体分片按order_id分片后台按订单号查询也可以但用户中心的查询就要做广播路由所以往往需要冗余一份用户订单索引表。另一个高频问题是ShardingSphere官方文档常提到的分布式表不能有主键的坑。准确说不是不能有主键而是全局主键不能依赖数据库自增因为每个分片各自自增会导致主键重复。解决方案很多雪花算法生成全局唯一ID美团Leaf做号段模式或者用UUID但去掉横杠变成单向有序。我在项目里常用雪花ID但要注意时钟回拨问题面试时能说出这个细节也非常加分。分库分表后的查询难题也很值得聊。比如原来一条SQL按非分片键查询现在需要同时查多个分片再合并内存排序。你可以说用ShardingSphere的分布式查询能力但底层本质是结果集归并数据量大了有性能瓶颈所以平时还是要强制走分片键。5. 设计模式与算法这两块最容易速成但也最暴露底子5.1 设计模式从源码角度讲单例和策略模式设计模式被很多候选人当成背类图和UML这恰恰是最低效的方式。面试官看的是你有没有在实际代码里用过。比如单例模式他可以问DCL为什么要加volatile。标准答案是为了禁止指令重排序但更深一层是JMM的八大原子操作new Singleton()三步——分配内存、初始化对象、赋值引用在并发下可能出现半初始化对象加volatile后通过内存屏障保证有序性。再比如Spring里面的设计模式非常适合拿来当答案模板。BeanFactory就是工厂模式AOP是动态代理模式JdbcTemplate用了模板方法模式DispatcherServlet是门面模式。知道这些不是让你背概念而是体现你在阅读框架源码时注意到这些设计决策。策略模式我觉得最实用因为它能回答如何消除大量if-else这个问题。可以这样说把不同支付渠道封装成策略类实现同一个接口再用工厂或Map去注册和获取策略。但这里有个坑策略实例多了工厂里的Map初始化会很长所以可以引入Spring的ApplicationContext.getBeansOfType自动收集所有策略Bean按名称映射。5.2 算法题重点不是刷题数而是抽象问题的能力算法是很多人抗拒的模块但说实话它是最容易在短期内提升的。关键不是刷到500题而是掌握几种常见题型的思考框架。数组链表类要练双指针、快慢指针二叉树类要练DFS和BFS的模板动态规划类要练定义状态、状态转移、初始化、遍历顺序四步法回溯类就记选择-撤销的递归模板。面试时算法题有几条潜规则。第一先和面试官确认输入输出和边界条件比如链表为空怎么办数组元素是不是整数这能降低理解偏差。第二边写边讲思路不要闷头写。第三写完主动走一个测试用例。如果遇到没见过的题正确表达是我先想一个暴力解确认基线再优化。面试官不会因为你没有秒出最优解就否定你但会很反感那种一上来就背答案的候选人。算法的价值是考察你如何把一个模糊问题逐步抽象成数据结构操作的过程这个过程的思路远比最终的代码重要。5.3 快速提分的两个小技巧设计模式和算法就算时间紧张也值得花两个周末做针对性准备。设计模式我建议重点看八个单例、工厂、策略、模板方法、观察者、代理、装饰器、责任链。每个模式都去看一个Spring或JDK中的真实用法然后自己动手写一个最小例子。算法就按专题刷每类十道足够。LeetCode高频题里反转链表、二叉树的层序遍历、最长回文子串、爬楼梯、二叉搜索树最近公共祖先这几类出现频率极高。刷的时候不要只看题解可以隔天重写一遍写不出来就说明还没内化。6. 三轮自测方法从会背到会讲6.1 第一轮能否不看文档讲出核心原理很多人的复习方式是看一遍书就觉得自己会了结果一合上大脑一片空白。第一轮自测要求很简单拿出一张白纸把你今天复习的知识点写下来比如Redis持久化然后不看任何资料先讲清楚RDB和AOF各自的文件格式、触发机制、恢复流程、优缺点。讲不出来的地方就是你的知识盲区回到文档再啃一遍。这一步不要偷懒要让输出过程像真的在面试一样最好录下来。听录音的时候你会发现自己口语化表达里全是然后、那个、嗯这些习惯在面试时很减分。具体操作每周选三个大主题进行白纸复述每个主题至少连续讲十五分钟。我第一次用这个方法时讲述一个分布式事务的话题前两分钟还行后面就开始翻来覆去说同样的话这就是没真正吃透的表现。6.2 第二轮能否画出链路图和说出如果挂了怎么查第二轮自测更接近系统设计面试。选一个业务链路比如订单下单成功后扣库存、生成订单、发消息、更新缓存要求自己画出完整的调用拓扑标注每个环节用的中间件、数据库、缓存组件然后设想如果MQ宕机了订单还能不能创建如果缓存里库存数据不是最新消费者会不会看到超卖这些问题不是背的是逼着你把技术点合成一条故障链路。面试官经常会问线上出现问题怎么排查你不妨建立自己的排查习惯体系先看监控面板确认影响范围再看日志定位异常模块最后看中间件状态。这套思路放到任何系统都通用。如果你能做到一边画图一边说这里我用Redis做库存预扣用MQ做异步通知库存最终一致靠定时任务核对面试官就会相信你不只是用过这些中间件而是参与过方案设计。6.3 第三轮模拟面试的十五分钟表达法最后一轮是模拟面试。找一个同样准备面试的伙伴或者自己对着镜子、录音笔把一个知识点在十五分钟内讲完。这十五分钟怎么分配前两分钟讲背景和解决什么问题中间十分钟讲核心机制多用例子和类比最后三分钟讲实际项目中的取舍比如遇到什么坑、怎么优化。以高并发下的库存扣减为例你可以这样说首先说明库存扣减是高并发写入问题核心是防止超卖然后给出几种方案从数据库乐观锁到Redis预扣再到消息队列异步化最后复盘你项目里最终选择哪种方案为什么不用另一种。十五分钟讲完面试官基本会认为你有深度。我个人感受是这套自测方法的收益不仅体现在面试中。哪怕你最后不跳槽用这种方式把知识体系重新梳理一遍也能发现自己日常写代码时忽略的很多问题。金三银四只是一个时间节点真正的竞争力是你对技术的理解深度。分布式、中间件、高并发、数据库、设计模式、算法这六个方向没有一个是靠背诵就能过关的。按上面的三轮自测走一遍你自然会发现自己哪里弱然后把时间花在刀刃上。面试前最后几天我建议你不再做新题只翻自己写的白纸笔记和录音把已经会的东西练得更顺。最后想分享一个我常用的心理暗示面试不是去展示我知道多少而是去展示我能用这些知识解决什么问题。带着这个思路走进会议室结果一般都不会太差。