以上是蔚来后端岗位的真实面经,一面主要考察候选人的基础原理,二面考察场景设计能力,总的来说,我认为难度适中,这在我们真实工作中也是会经常会遇到的问题,下面我就上面的面试题,我做下自己的理解以及回答方式,并非标准答案,而且场景设计题也没有固定答案,实际回答时结合自己的项目经历替换例子即可。
一面:基础原理,不单单考八股文
1、ConcurrentHashMap 底层原理与 JDK8 优化
回答模板:"我按 JDK7 和 JDK8 对比答。JDK7 是 Segment 分段锁,Segment 继承 ReentrantLock,默认 16 个,并发度固定。JDK8 改成 Node 数组 + 链表 + 红黑树:桶为空时用 CAS 插入,桶非空时用 `synchronized` 锁住桶头节点,锁粒度从 Segment 降到单个桶;扩容支持多线程协助,用 ForwardingNode 标记已迁移的桶;size 统计改成 `baseCount + CounterCell[]`,类似 LongAdder。put 的关键流程是:哈希扰动、定位桶、空桶 CAS、非空加锁插入、`addCount` 判断是否扩容。链表长度到 8 并且数组长度到 64 才树化。get 不加锁,靠 volatile 保证可见性。它不允许 null key 和 null value,因为并发下无法区分“不存在”和“值就是 null”。size 是弱一致的,只能作为监控参考,不能做业务判断。"
2、 慢查询定位与 Explain 重点字段
回答模板:“慢查询我先开 slow_query_log,设置 long_query_time,用 pt-query-digest 按总耗时排序定位,再结合 show processlist 和 APM 找到具体接口。 Explain 我重点看五个字段:type 看访问类型,从好到差是 const、eq_ref、ref、range、index、ALL;key 看实际用了哪个索引;key_len 看联合索引用了几列;rows 看预估扫描行数;Extra 看 Using index 覆盖索引、Using filesort、Using temporary、Using index condition。 优化上遵循最左前缀,避免在索引列上做函数和隐式转换,深分页用延迟关联或游标,大表关联让小表驱动。MySQL 8.0.18 以上可以用 EXPLAIN ANALYZE 看真实耗时。”
二面:场景题
3、蔚来用户购车、试驾预约如何防止超卖和重复提交?
思路分析:
- 超卖本质是“读库存、判断、扣减”不是原子操作;重复提交本质是缺幂等键。
- 分三层:入口限流、幂等控制、库存原子扣减。
- 高并发用 Redis 预扣,数据库唯一索引和定时对账兜底。
回答模板:“我会分三层设计。入口层用网关限流、验证码和前端防抖,先挡住大部分无效流量。 幂等层用业务唯一号加唯一索引兜底。下单前申请幂等 Token 存 Redis,提交时用 SET NX 消费;订单状态用 CAS 更新,比如 update order set status='PAID' where id=? and status='UNPAID',根据影响行数判断是否重复处理。 库存层优先用数据库原子扣减:update stock set stock=stock-1 where sku_id=? and stock>=1,判断影响行数,为 0 就是售罄。QPS 更高时改成 Redis Lua 预扣,再通过 MQ 异步落库,用本地消息表、定时对账和补偿保证最终一致。热点 SKU 还可以做库存分桶,降低单行锁竞争。 试驾预约按门店、日期、时段建名额,用 user_id + store_id + date 唯一索引防重复预约,再用状态机和延迟消息处理超时释放。”
4、微服务架构下,蔚来多个服务之间如何解决接口幂等性问题?
思路分析:
幂等不是拒绝重复,而是重复执行结果一致。
按场景选:唯一索引、幂等 Token、状态机 CAS、Redis SETNX、消费去重表。
回答模板:”接口幂等我会先定义幂等键,一般是业务类型加业务号,然后分场景选方案。
创建类操作用数据库唯一索引最可靠,冲突时返回已存在的结果;表单和下单用幂等 Token,Redis `SET NX` 抢占,处理完缓存结果,重复请求直接返回第一次的结果;状态流转类用 CAS,根据影响行数判断;MQ 消费用消费记录表,`message_id + consumer_group` 唯一索引。
高并发场景用 Redis `SET NX EX` 做并发控制,数据库唯一索引做最终兜底,再加定时对账。关键是幂等键的过期时间要覆盖重试窗口,幂等记录要定期归档。“
5、高并发积分、会员权益的行锁竞争如何优化?
思路分析:
行锁竞争来自热点行、长事务和高并发更新。
四个方向:缩短事务、拆分热点、异步化、限流隔离。
回答模板:“积分和权益的行锁竞争,本质是同一行被高并发更新。我从四个方向优化。
第一,缩短事务,事务里不做 RPC 和发消息,用原子 SQL 减少查询和更新的往返。
第二,拆分热点,积分账户按 bucket_no 分桶,更新时轮询选桶,查询时 SUM 汇总;或者按 user_id 哈希到 MQ 固定分区,单消费者串行处理。
第三,异步化,用 Redis Lua 预扣、异步落库、定时对账,适合允许最终一致的场景。
第四,冲突不高时用乐观锁 version,冲突高时做限流隔离,避免重试放大流量。另外多行更新要固定加锁顺序避免死锁,还要确认 where 条件走了索引,否则行锁会扩大范围。”
正文中仅详细解析了前5道核心题目。在Java笔记 小李版有完整版的(含二面场景题详解) 及 PDF模板 已整理打包,,我们一起进步!