阿里巴巴 Java 后端面经(2024 秋招)
岗位:Java 后端开发工程师(淘天集团)
背景:985 硕士,两段大厂实习,一篇 A 类会议论文
结果: offer,评级 P5+
时间线:8.20 投递 → 8.28 一面 → 9.5 二面 → 9.12 三面 → 9.20 HR 面 → 9.25 offer
一面(技术面,1h 10min)
面试官是一位 P7 的资深工程师,气质沉稳,主要围绕简历上的第一个项目(工业级推荐系统)展开。
算法题(35min)
LeetCode 146. LRU Cache
要求手写完整的 LRUCache 类,包括 get 和 put 方法。我使用哈希表 + 双向链表实现,15 分钟完成编码。
class DLinkedNode:
def __init__(self, key=0, value=0):
self.key = key
self.value = value
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.cache = {}
self.head = DLinkedNode()
self.tail = DLinkedNode()
self.head.next = self.tail
self.tail.prev = self.head
self.capacity = capacity
self.size = 0
def get(self, key: int) -> int:
if key not in self.cache:
return -1
node = self.cache[key]
self.move_to_head(node)
return node.value
def put(self, key: int, value: int) -> None:
if key in self.cache:
node = self.cache[key]
node.value = value
self.move_to_head(node)
else:
node = DLinkedNode(key, value)
self.cache[key] = node
self.add_to_head(node)
self.size += 1
if self.size > self.capacity:
removed = self.remove_tail()
del self.cache[removed.key]
self.size -= 1
def add_to_head(self, node: DLinkedNode):
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def remove_node(self, node: DLinkedNode):
node.prev.next = node.next
node.next.prev = node.prev
def move_to_head(self, node: DLinkedNode):
self.remove_node(node)
self.add_to_head(node)
def remove_tail(self) -> DLinkedNode:
node = self.tail.prev
self.remove_node(node)
return node
追问:
- 如果要支持并发访问,你会怎么改?(我答:加读写锁,或者用
ConcurrentHashMap+ReentrantReadWriteLock) LinkedHashMap怎么实现 LRU?(按访问顺序排序的LinkedHashMap,设置accessOrder=true并覆写removeEldestEntry)
项目深挖(25min)
围绕实习中的推荐系统项目:
- 特征工程链路:如何处理高维稀疏特征?
- 答:使用 Embedding 层做维度压缩,对 ID 类特征做 Hash Bucket 处理。
- 模型选型:为什么选 DeepFM 而不是 Wide & Deep?
- 答:DeepFM 自动学习二阶特征交叉,不需要手动做特征工程,在点击率预估上效果更好。
- 线上推理延迟:如何优化?
- 答:模型量化(FP32 → FP16)、特征缓存(Redis 预取)、并行张量计算(TensorRT)。
Java 基础(10min)
HashMap的扩容机制?(阈值 0.75,resize 时链表/红黑树重哈希)synchronized和ReentrantLock的区别?(语法、功能、公平锁、中断响应)
二面(技术 + 架构,1h)
二面面试官是所在部门的技术负责人,P8 级别。风格偏宏观,喜欢问"如果让你来设计…"
算法题(25min)
LeetCode 23. 合并 K 个升序链表
要求时间复杂度最优。我使用最小堆(优先队列):
import heapq
from typing import List, Optional
class ListNode:
# ...
def __lt__(self, other):
return self.val < other.val
def mergeKLists(lists: List[Optional[ListNode]]) -> Optional[ListNode]:
heap = []
dummy = ListNode(0)
curr = dummy
for lst in lists:
if lst:
heapq.heappush(heap, lst)
while heap:
node = heapq.heappop(heap)
curr.next = node
curr = curr.next
if node.next:
heapq.heappush(heap, node.next)
return dummy.next
追问:如果数据量极大(TB 级别),内存放不下怎么办?(外部归并排序,分批读入内存生成有序子文件,再 K 路归并)
系统设计(30min)
设计一个秒杀系统
我按 4S 框架回答:
- Scenario:日均 DAU 1 亿,秒杀商品库存 1000,预期峰值 QPS 10 万
- Service:拆分为网关层、活动服务、库存服务、订单服务、支付服务
- Storage:
- 活动信息:Redis(高并发读取)
- 库存扣减:Redis Lua 原子脚本
- 订单数据:分库分表 MySQL
- Scale:
- 限流:令牌桶 + Nginx rate limit
- 削峰:Kafka 消息队列
- 防超卖:Redis 原子递减 + 异步落库
面试官追问:如果 Redis 挂了怎么办?(预热库存到本地缓存 + 降级到排队等待页面)
软性问题(5min)
如果业务和技术的目标冲突,你会怎么处理?(举了一个实习中的真实案例说明沟通方式)
三面(总监面,40min)
三面是淘天某业务线技术总监,几乎没有写代码题,全是开放性问题。
- 你最自豪的一个技术决策是什么?
- 答:在实习中将一个 Flink 双流 Join 的 CPU 占用从 80% 降到 30%,主要通过状态后端调优(RocksDB 增量 checkpoint)和水位线对齐优化。
- 如果让你从零设计一个电商搜索引擎,你会怎么做?
- 答:倒排索引 + 分词 + TF-IDF/BM25 基础排序 + 机器学习精排(LambdaMART),并提到冷热数据分离和缓存策略。
- 你最想加入阿里的哪个技术团队?为什么?
HR 面(30min)
常规 HR 面,主要关注:
- 期望薪资
- 手里有几个 offer?(如实回答有字节和美团)
- 为什么选择阿里而不是字节?
- 未来 3-5 年的职业规划
面试复盘与建议
| 维度 | 表现 | 建议 |
|---|---|---|
| 算法 | ⭐⭐⭐⭐ 两道题都 AC | 重点准备 LeetCode Hot 100,特别是链表、二叉树、动态规划 |
| 项目 | ⭐⭐⭐⭐⭐ 准备充分 | 每个项目准备 3 个技术亮点和 2 个难点 |
| 系统设计 | ⭐⭐⭐⭐ 框架清晰 | 记住 4S 法,多画架构图辅助表达 |
| 软技能 | ⭐⭐⭐⭐ 正常发挥 | 提前准备「自豪的项目」「失败的经历」两个故事 |
核心教训:阿里的面试非常看重"言之有物"——每一个回答都要能讲出技术细节和权衡过程。泛泛而谈会被打断追问。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。