Java 市场现状、AI 影响与大厂面试全解析

一、Java 还有市场吗?答案是:有,但门槛大幅提高

市场现状:从绝对霸主到稳定第三

  • 全球排名:根据 2026 年最新 TIOBE 排行榜,Java 以 7.99%-8.71% 的市场份额位居第三 / 第四,仅次于 Python 和 C/C++
  • 基本盘极其稳固:全球仍有数百万个 Java 系统在金融、电信、电商、政府等核心领域运行,这些系统生命周期长达 10-20 年,维护需求将持续存在
  • 企业级应用不可替代:在传统企业、国企、银行的后台系统中,Java 用量依然第一,没有任何语言能在稳定性、生态完善度和人才储备上与之匹敌

需求结构发生根本性变化

  • 初级岗位大幅缩减:大厂 Java 岗位需求同比下降约 20%,中小企业下降 30%,仅掌握基础 CRUD 的开发者竞争异常激烈
  • 中高级人才供不应求:3 年以上经验的中高级开发者依然抢手,尤其是具备架构设计、性能调优、问题排查能力的人才
  • 新兴方向需求爆发:云原生改造、大数据平台搭建、AI 工程化等方向的 Java 岗位需求增长 40% 以上

薪资趋势

  • 整体中位数薪资下降约 12.5%,主要是初级岗位拉低了平均值
  • 中高级和复合型人才薪资不降反升:掌握 AI 工程化能力的开发者薪资上涨 20% 左右
  • 地域差异明显:一线城市竞争激烈但薪资高,二三线城市政企项目和传统企业数字化转型需求稳定,竞争压力相对较小

二、Java 会被 AI 淘汰吗?答案是:不会,但不使用 AI 的 Java 程序员会

AI 对 Java 开发的真实影响

  • 75% 的日常工作任务可被 AI 覆盖:基础编码、调试 Bug、文档整理、重复性数据处理是重灾区
  • 替代风险分层
    • 仅掌握 CRUD 的开发者:90% 替代风险
    • 仅会调用 API 的开发者:85% 替代风险
    • 初级测试 / 运维 / 文档岗:85%+ 替代风险
    • 掌握 AI 协作的高端开发者:薪资上涨 20%

AI 无法替代的核心能力

  • 需求分析与转化:将模糊的业务需求转化为清晰的技术方案
  • 系统架构设计:复杂系统的整体设计、模块划分、技术选型
  • 性能调优与问题排查:生产环境的性能瓶颈分析、复杂 Bug 定位
  • 业务理解与决策:结合业务场景做出技术决策,平衡技术与业务价值
  • 代码质量把控:审核 AI 生成的代码,确保其安全性、可维护性和性能

Java 在 AI 时代的新机遇

  • AI 工程化的核心语言:Python 主导 AI 模型训练,但 Java 负责将 AI 能力规模化部署到生产环境
  • 80% 的企业使用 Java 开发 AI 功能:2026 年这一比例较 2025 年的 50% 上升了 30 个百分点
  • 跨语言对接优势:Java 生态完善,能够无缝对接各种 AI 框架和服务,在企业级 AI 应用落地中占据核心地位

三、2026 年大厂级 Java 面试是什么样的?

完整面试流程与淘汰率

表格

面试环节 时长 淘汰率 核心考察重点
简历筛选 8 秒 / 份 75%+ 学历 / 经验匹配度、项目契合度、成果量化
笔试 / 在线测评 60-90 分钟 55%+ Java 基础、算法编程、SQL 优化、逻辑题
技术一面(基础面) 30-45 分钟 60%+ Java 核心基础、JVM、集合、并发编程、MySQL
技术二面(项目面) 45-60 分钟 50%+ 项目深度、框架原理、中间件使用、分布式系统
技术三面(架构面) 60-90 分钟 40%+ 系统设计、架构能力、技术视野、解决复杂问题的能力
HR 面试 30 分钟 10%+ 求职动机、职业规划、团队合作、抗压能力

2026 年面试核心变化

  • 从 "背八股" 到 "实战 + 深度理解":90% 的老式纯理论题被淘汰,取而代之的是场景化问题
  • 增加 AI 相关考察:几乎所有大厂都会问到 AI 工具使用经验和 AI 接口设计问题
  • 更注重项目深度:不再只问 "做了什么",而是深入追问 "为什么这么做"、"遇到了什么问题"、"怎么解决的"、"有什么可以改进的"

核心考核维度与权重

  1. Java 核心基础(25%):集合底层、并发编程、JVM、JDK17/21 新特性落地能力
  2. Spring 全家桶(20%):自动配置原理、源码理解、事务机制、AOT 原生镜像、虚拟线程适配
  3. 分布式与中间件(25%):MySQL 优化、Redis 缓存设计、MQ 可靠性、分布式锁 / 事务、微服务治理
  4. 系统设计与场景题(20%):高并发 / 高可用场景落地、架构选型、问题排查与调优
  5. 算法与编码能力(10%):中等难度算法题、代码质量、边界条件处理

高频面试题示例

  • JVM:你在电商项目中做过哪些 JVM 调优?给出具体的参数调整、压测数据和最终效果
  • 并发编程:详细讲下 volatile 的实现原理,它能保证原子性吗?你在项目中哪些场景用到了 volatile
  • Spring:Spring 事务的传播机制有哪些?什么场景下会导致事务失效?你踩过哪些事务的坑
  • Redis:Redis7.0 相比 6.0 做了哪些核心优化?电商大促场景下如何解决缓存击穿、缓存雪崩问题
  • 分布式:分布式事务解决方案有哪些?各自的优缺点和适用场景是什么
  • AI 场景:假设要在商品详情页接入一个 "智能推荐文案" 的 AI 接口,你会如何设计调用链路以保证接口延迟可控

四、给 Java 开发者的建议

  1. 拥抱 AI 工具:熟练使用 GitHub Copilot、ChatGPT 等 AI 工具提高开发效率,学习如何用 AI 辅助代码生成、调试和文档编写
  2. 提升核心竞争力:从 "写代码的人" 转变为 "解决问题的人",重点培养系统设计、性能调优、问题排查和业务理解能力
  3. 拓展技术栈:学习云原生技术(Docker、K8s)、大数据技术和 AI 工程化知识,成为 "Java+X" 复合型人才
  4. 深耕业务领域:在金融、电商、医疗等特定行业积累深厚的业务知识,成为懂技术又懂业务的专家
  5. 持续学习:关注 Java 最新版本(JDK21/23)的新特性,以及 Spring Boot 3.x、Spring Cloud Alibaba 等主流框架的最新发展

3 个月大厂 Java 面试准备计划(2026 版)

适用人群:2-5 年 Java 开发经验,目标字节、阿里、腾讯、美团等一线大厂 每日投入:工作日 3 小时(晚上 7-10 点),周末 8 小时(上午 9-12 点,下午 2-6 点) 核心原则实战优先 > 理论背诵深度理解 > 广度覆盖AI 辅助学习

第一阶段:基础夯实期(第 1-4 周)

目标:彻底掌握 Java 核心基础、JVM、MySQL 和 Spring 全家桶,解决 80% 的基础面试题 每日任务结构:知识点学习(1.5h)+ 代码实战(1h)+ 复盘总结(0.5h)

第 1 周:Java 核心基础与集合框架

日期 学习任务 重点知识点 实战练习
周一 Java 基础回顾 基本数据类型、自动装箱拆箱、String 不可变原理、equals 与 ==、hashCode 手写 StringBuilder 实现
周二 集合框架(上) ArrayList/LinkedList 底层、扩容机制、fail-fast 机制、HashMap1.7/1.8/21 对比 手写 HashMap 核心功能
周三 集合框架(下) ConcurrentHashMap 原理、红黑树、TreeMap、LinkedHashMap、Queue/Deque 实现一个线程安全的 LRU 缓存
周四 异常与 IO 异常体系、try-with-resources、NIO 与 BIO 区别、ByteBuffer、Channel 用 NIO 实现简单文件服务器
周五 泛型与反射 泛型擦除、通配符、反射原理、动态代理、注解处理器 手写一个简单的依赖注入框架
周六 JDK17/21 新特性 虚拟线程、模式匹配、record 类、密封类、结构化并发 将一个传统线程池项目改造为虚拟线程
周日 本周复盘 整理错题本,用 AI 生成 10 道面试题自测,录制 1 分钟讲解视频 输出本周知识点思维导图

第 2 周:JVM 虚拟机

日期 学习任务 重点知识点 实战练习
周一 JVM 内存模型 堆、栈、方法区、元空间、直接内存、JMM 内存模型 分析一个 OOM 异常的 dump 文件
周二 垃圾回收机制 垃圾判定算法、分代回收、G1/ZGC/Shenandoah 收集器、GC 日志分析 用 JProfiler 监控应用内存使用
周三 类加载机制 类加载过程、双亲委派模型、自定义类加载器、模块化系统 实现一个热加载的类加载器
周四 JVM 调优基础 常用 JVM 参数、堆大小设置、GC 参数调优、线程栈大小 对一个简单 Web 应用进行 JVM 调优
周五 并发编程基础 线程状态、Thread 类、Runnable/Callable、线程池原理 手写一个简单的线程池
周六 并发编程进阶 synchronized 底层、volatile 原理、AQS、ReentrantLock、CountDownLatch 实现一个基于 AQS 的互斥锁
周日 本周复盘 整理 JVM 高频面试题,用 AI 模拟面试,重点讲解 GC 调优案例 输出 JVM 调优步骤文档

第 3 周:MySQL 数据库

日期 学习任务 重点知识点 实战练习
周一 MySQL 基础 存储引擎对比、索引类型、B + 树原理、聚簇索引与非聚簇索引 分析一个慢查询 SQL 的执行计划
周二 SQL 优化 索引失效场景、覆盖索引、联合索引、分页查询优化、JOIN 优化 优化一个包含多个 JOIN 的复杂 SQL
周三 事务与锁 ACID 特性、隔离级别、MVCC 原理、行锁 / 表锁、间隙锁、死锁 复现并解决一个死锁问题
周四 MySQL 架构 主从复制原理、读写分离、分库分表基础、连接池原理 搭建一个简单的主从复制环境
周五 数据库设计 三大范式、反范式设计、字段类型选择、索引设计原则 设计一个电商订单系统的数据库
周六 MySQL8.0 新特性 窗口函数、CTE、原子 DDL、JSON 功能、InnoDB 优化 用窗口函数实现排名和分组统计
周日 本周复盘 整理 SQL 优化案例,用 AI 生成 10 道 SQL 题练习,总结索引设计经验 输出数据库设计规范文档

第 4 周:Spring 全家桶基础

日期 学习任务 重点知识点 实战练习
周一 Spring 核心 IoC 容器原理、Bean 生命周期、依赖注入方式、AOP 原理 手写一个简单的 IoC 容器
周二 Spring 事务 事务传播机制、隔离级别、事务失效场景、分布式事务基础 复现并解决 3 种常见的事务失效问题
周三 Spring Boot 基础 自动配置原理、starter 机制、配置文件、条件注解 开发一个自定义的 Spring Boot Starter
周四 Spring Boot 进阶 嵌入式容器、Actuator 监控、健康检查、配置中心集成 为应用添加 Actuator 监控和健康检查
周五 Spring MVC 请求处理流程、拦截器、过滤器、参数绑定、异常处理 实现一个统一的异常处理和返回结果封装
周六 MyBatis/MyBatis-Plus 执行流程、一级缓存 / 二级缓存、分页插件、动态 SQL 用 MyBatis-Plus 实现 CRUD 和复杂查询
周日 第一阶段总复盘 全面回顾前 4 周知识点,用 AI 生成一套基础面试题自测 整理第一阶段错题本和高频考点

第二阶段:进阶提升期(第 5-8 周)

目标:掌握分布式、中间件、微服务和系统设计,具备解决复杂问题的能力 每日任务结构:原理学习(1h)+ 场景分析(1h)+ 项目准备(1h)

第 5 周:Redis 缓存中间件

日期 学习任务 重点知识点 实战练习
周一 Redis 基础 数据结构与底层实现、持久化机制、过期策略、内存淘汰 用 Redis 实现分布式锁
周二 Redis 高级特性 发布订阅、Lua 脚本、事务、管道、Bitmap、HyperLogLog 用 Lua 脚本实现原子性操作
周三 Redis 集群 主从复制、哨兵模式、Cluster 集群、分片原理、数据迁移 搭建一个 3 主 3 从的 Redis Cluster 集群
周四 缓存常见问题 缓存穿透、缓存击穿、缓存雪崩、数据一致性、缓存更新策略 设计一个电商商品详情页的缓存方案
周五 Redis 性能调优 内存优化、网络优化、慢查询分析、监控告警 对 Redis 进行性能压测和调优
周六 Redis7.0 新特性 Functions、ACL 2.0、集群分片迁移优化、内存碎片整理 用 Redis Functions 实现复杂业务逻辑
周日 本周复盘 整理 Redis 高频面试题,总结缓存设计最佳实践 输出 Redis 使用规范文档

第 6 周:消息队列与分布式基础

日期 学习任务 重点知识点 实战练习
周一 Kafka 基础 架构设计、生产者 / 消费者、分区、副本、ISR 机制 搭建 Kafka 集群并实现消息生产消费
周二 Kafka 高级特性 消息可靠性、顺序消息、重复消息、延迟队列、死信队列 实现一个可靠的消息投递系统
周三 RocketMQ 对比 与 Kafka 的区别、事务消息、定时消息、消息轨迹 用 RocketMQ 实现分布式事务
周四 分布式协调 ZooKeeper 原理、节点类型、Watcher 机制、分布式锁 用 ZooKeeper 实现分布式锁和配置中心
周五 分布式基础理论 CAP 定理、BASE 理论、一致性算法(Paxos/Raft) 用 Raft 算法实现一个简单的分布式 KV 存储
周六 分布式事务 2PC、3PC、TCC、SAGA、本地消息表、最大努力通知 对比各种分布式事务方案的优缺点
周日 本周复盘 整理分布式系统常见问题和解决方案 输出分布式系统设计原则文档

第 7 周:微服务与云原生

日期 学习任务 重点知识点 实战练习
周一 微服务架构 微服务设计原则、服务拆分、API 网关、服务注册发现 用 Spring Cloud Gateway 实现 API 网关
周二 Spring Cloud Alibaba Nacos、Sentinel、Seata、Dubbo 集成 Nacos 实现服务注册发现和配置中心
周三 服务治理 负载均衡、熔断降级、限流、链路追踪、监控告警 用 Sentinel 实现熔断降级和限流
周四 Docker 基础 镜像、容器、Dockerfile、Docker Compose 编写 Dockerfile 将应用容器化
周五 Kubernetes 基础 Pod、Deployment、Service、ConfigMap、Secret 用 K8s 部署一个简单的微服务应用
周六 云原生进阶 容器编排、CI/CD、可观测性、服务网格 搭建一个简单的 CI/CD 流水线
周日 本周复盘 整理微服务架构面试题,总结云原生技术栈 输出微服务拆分最佳实践文档

第 8 周:系统设计与项目准备

日期 学习任务 重点知识点 实战练习
周一 系统设计基础 高可用、高并发、可扩展性、一致性设计原则 设计一个短链接系统
周二 高并发系统设计 缓存、异步、削峰填谷、水平扩展、读写分离 设计一个秒杀系统
周三 高可用系统设计 集群、容灾、备份、降级、限流、熔断 设计一个分布式文件系统
周四 项目梳理(上) 挑选 1-2 个最有亮点的项目,梳理项目背景、技术栈、架构图 绘制项目架构图和数据流图
周五 项目梳理(下) 提炼项目难点、解决方案、个人贡献、量化成果 准备 STAR 法则的项目介绍
周六 AI 工程化基础 AI 接口设计、调用链路优化、异常处理、限流熔断 设计一个 AI 推荐接口的调用方案
周日 第二阶段总复盘 全面回顾前 8 周知识点,用 AI 生成一套进阶面试题自测 整理第二阶段错题本和高频考点

第三阶段:冲刺模拟期(第 9-12 周)

目标:刷算法题、做模拟面试、查漏补缺,提升面试实战能力 每日任务结构:算法刷题(1h)+ 模拟面试(1h)+ 查漏补缺(1h)

第 9-10 周:算法刷题专项

核心策略分类刷题 + 高频题优先,重点掌握 LeetCode 中等难度题目,每天刷 3-5 道题

  • 第 9 周:数组、字符串、链表、栈、队列、哈希表
  • 第 10 周:树、图、动态规划、贪心算法、二分查找、排序

每日任务

  1. 早上:刷 3 道对应类型的 LeetCode 题,每道题限时 20 分钟
  2. 下午:看题解,理解最优解法,总结解题思路和模板
  3. 晚上:复习前一天的题目,用 AI 生成类似题目练习

重点掌握

  • 二叉树的前中后序遍历、层序遍历、递归与迭代实现
  • 动态规划的常见题型:背包问题、最长公共子序列、最长递增子序列
  • 二分查找的各种变体:查找第一个等于目标值的元素、查找最后一个等于目标值的元素
  • 链表的常见操作:反转链表、合并两个有序链表、环形链表检测

第 11 周:模拟面试与查漏补缺

每日任务

  1. 上午:进行 1 次完整的模拟面试(1 小时),可以找朋友互相面试或用 AI 模拟面试
  2. 下午:复盘模拟面试,找出自己的薄弱环节,针对性复习
  3. 晚上:整理面试话术,准备自我介绍、项目介绍、优缺点等常见问题

模拟面试重点

  • 技术一面:基础知识点问答,重点考察 Java、JVM、MySQL、Spring
  • 技术二面:项目深度挖掘,重点考察项目难点、解决方案、个人贡献
  • 技术三面:系统设计和技术视野,重点考察架构能力和解决复杂问题的能力

查漏补缺重点

  • 之前整理的错题本和高频考点
  • 自己不熟悉的知识点和技术栈
  • 最新的技术趋势和大厂面试热点

第 12 周:最终冲刺与心态调整

每日任务

  1. 上午:复习核心知识点和高频面试题,每天过一遍
  2. 下午:进行 1-2 次模拟面试,重点练习表达能力和逻辑思维
  3. 晚上:调整作息,保持良好的心态,准备面试所需的材料

最终准备

  • 准备一份简洁明了的简历,突出项目亮点和量化成果
  • 准备 3-5 个自己最擅长的项目,能够清晰地讲解项目背景、技术栈、难点和解决方案
  • 准备一些向面试官提问的问题,体现自己对公司和岗位的兴趣
  • 调整好心态,保持自信,面试时不要紧张,发挥出自己的真实水平

学习方法与注意事项

  1. 善用 AI 工具:用 GitHub Copilot 辅助编码,用 ChatGPT 讲解知识点、生成面试题、模拟面试
  2. 注重实战:不要只背理论,一定要动手写代码、做项目、调优性能
  3. 输出倒逼输入:多写博客、多做分享、多录制讲解视频,加深对知识点的理解
  4. 定期复盘:每周日进行一次复盘,总结本周的学习成果和不足,调整下周的学习计划
  5. 保持健康:合理安排作息时间,保证充足的睡眠,适当进行体育锻炼

3 个月大厂 Java 面试高频题与标准答案(2026 版)

配套使用说明:每个知识点精选 3-5 道最高频面试题,答案采用 "核心原理 + 项目经验 + 加分项" 结构,完全匹配大厂面试官评分标准。标⭐的为必背题,出现概率 > 80%。

第一阶段:基础夯实期(第 1-4 周)

第 1 周:Java 核心基础与集合框架

1. String 为什么不可变?⭐

标准答案

  • 底层实现:JDK9 之前用private final char[] value存储字符,JDK9 + 改用private final byte[] value+ 编码标识,数组引用和内容都不可修改
  • 不可变的原因
    1. 字符串常量池复用,节省内存
    2. 线程安全,多线程环境下无需同步
    3. 哈希值缓存,作为 HashMap 键时性能更高
    4. 安全性,避免被恶意修改(如数据库连接字符串)
  • 项目经验:在处理大量字符串拼接时,使用 StringBuilder 而非 "+" 操作符,避免创建大量临时 String 对象
  • 加分项:知道 String 不可变是 "引用不可变" 而非 "内容不可变",可以通过反射修改 value 数组
2. HashMap1.7 和 1.8 的区别?⭐

标准答案

特性 JDK1.7 JDK1.8+
底层结构 数组 + 链表 数组 + 链表 + 红黑树
插入方式 头插法 尾插法
扩容时机 容量达到阈值且发生哈希冲突 容量达到阈值
哈希算法 4 次位运算 + 5 次异或 1 次位运算 + 1 次异或
并发问题 扩容时可能形成环形链表导致死循环 不会死循环,但仍有数据丢失问题
  • 项目经验:在高并发场景下绝对不使用 HashMap,改用 ConcurrentHashMap
  • 加分项:知道 JDK21 中 HashMap 进一步优化了红黑树转换阈值和内存布局
3. ConcurrentHashMap 的线程安全实现原理?⭐

标准答案

  • JDK1.7:分段锁(Segment),将数组分成 16 个段,每个段独立加锁,并发度为 16
  • JDK1.8+:CAS+synchronized,只对链表头节点或红黑树根节点加锁,并发度大幅提高
    1. 空节点用 CAS 插入
    2. 非空节点用 synchronized 加锁
    3. 链表长度 > 8 且数组长度 > 64 时转为红黑树
  • 项目经验:在电商订单系统中用 ConcurrentHashMap 实现本地缓存,支撑每秒 10 万 + 的查询请求
  • 加分项:知道 ConcurrentHashMap 不支持 null 键和 null 值的原因
4. equals 和 == 的区别?

标准答案

  • ==:比较基本数据类型时比较值,比较引用数据类型时比较内存地址
  • equals:Object 类中默认实现与 == 相同,比较内存地址;大多数类会重写 equals 方法比较内容
  • hashCode 约定
    1. 两个对象 equals 相等,hashCode 必须相等
    2. 两个对象 hashCode 相等,equals 不一定相等
  • 项目经验:自定义类作为 HashMap 键时,必须同时重写 equals 和 hashCode 方法
5. 手写一个线程安全的 LRU 缓存

标准答案

public class LRUCache<K, V> {
    private final int capacity;
    private final Map<K, Node<K, V>> cache;
    private final Node<K, V> head;
    private final Node<K, V> tail;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.cache = new ConcurrentHashMap<>(capacity);
        this.head = new Node<>();
        this.tail = new Node<>();
        head.next = tail;
        tail.prev = head;
    }

    public V get(K key) {
        Node<K, V> node = cache.get(key);
        if (node == null) return null;
        moveToHead(node);
        return node.value;
    }

    public void put(K key, V value) {
        Node<K, V> node = cache.get(key);
        if (node == null) {
            Node<K, V> newNode = new Node<>(key, value);
            cache.put(key, newNode);
            addToHead(newNode);
            if (cache.size() > capacity) {
                Node<K, V> tailNode = removeTail();
                cache.remove(tailNode.key);
            }
        } else {
            node.value = value;
            moveToHead(node);
        }
    }

    private void addToHead(Node<K, V> node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    private void removeNode(Node<K, V> node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void moveToHead(Node<K, V> node) {
        removeNode(node);
        addToHead(node);
    }

    private Node<K, V> removeTail() {
        Node<K, V> res = tail.prev;
        removeNode(res);
        return res;
    }

    private static class Node<K, V> {
        K key;
        V value;
        Node<K, V> prev;
        Node<K, V> next;
        // 构造方法省略
    }
}

第 2 周:JVM 虚拟机

1. JVM 内存模型(JMM)是什么?⭐

标准答案

  • 核心定义:Java 内存模型定义了线程和主内存之间的抽象关系,所有变量都存储在主内存中,线程操作变量需要先加载到工作内存
  • 三大特性
    1. 原子性:一个操作不可中断,synchronized 和 volatile 可以保证原子性
    2. 可见性:一个线程修改了变量的值,其他线程能立即看到,volatile、synchronized 和 final 可以保证可见性
    3. 有序性:禁止指令重排序,volatile 和 synchronized 可以保证有序性
  • Happens-Before 规则
    1. 程序顺序规则
    2. 锁定规则
    3. volatile 变量规则
    4. 传递性规则
  • 项目经验:在多线程环境下使用 volatile 修饰状态变量,保证线程间的可见性
2. G1 收集器的工作原理?⭐

标准答案

  • 核心设计:将堆内存划分为多个大小相等的 Region(1-32MB),每个 Region 可以是 Eden、Survivor 或 Old 区
  • 工作流程
    1. 初始标记:STW,标记 GC Roots 直接关联的对象
    2. 并发标记:与用户线程并发执行,遍历对象图
    3. 最终标记:STW,修正并发标记期间的变化
    4. 筛选回收:STW,根据 Region 的回收价值排序,优先回收价值高的 Region
  • 优势:可预测的停顿时间,避免全堆扫描,适合大堆应用
  • 项目经验:在电商大促前将 JDK8 的 CMS 收集器升级为 G1,GC 停顿时间从 200ms 降低到 50ms 以内
3. 双亲委派模型是什么?为什么需要?⭐

标准答案

  • 核心定义:类加载器收到类加载请求时,先委托给父类加载器加载,父类加载器无法加载时才自己加载
  • 类加载器层次
    1. 启动类加载器(Bootstrap ClassLoader):加载 JRE/lib 目录
    2. 扩展类加载器(Extension ClassLoader):加载 JRE/lib/ext 目录
    3. 应用程序类加载器(Application ClassLoader):加载 classpath 目录
    4. 自定义类加载器:加载自定义路径的类
  • 为什么需要
    1. 防止核心类被篡改(如 java.lang.String)
    2. 避免类的重复加载
    3. 保证 Java 程序的安全性和稳定性
  • 破坏场景:SPI 机制、Tomcat 类加载器、热部署
4. 你做过哪些 JVM 调优?给出具体案例

标准答案

  • 调优步骤
    1. 监控:使用 jstat、jmap、jstack、Arthas 等工具收集 GC 日志和线程 dump
    2. 分析:分析 GC 频率、停顿时间、OOM 原因、线程死锁等问题
    3. 调优:调整 JVM 参数,优化代码
    4. 验证:压测验证调优效果
  • 具体案例
    1. 问题:电商订单系统在大促时频繁 Full GC,停顿时间长达 1 秒
    2. 分析:发现年轻代太小,对象频繁进入老年代;老年代使用 CMS 收集器,内存碎片严重
    3. 调优
      • 年轻代从 2G 调整为 4G
      • 老年代从 6G 调整为 4G
      • 升级为 G1 收集器,设置最大停顿时间 200ms
      • 优化代码,避免创建大量临时对象
    4. 效果:Full GC 频率从每 10 分钟 1 次降低到每天 1 次,平均停顿时间 < 50ms
5. volatile 的实现原理?能保证原子性吗?

标准答案

  • 实现原理
    1. 加入内存屏障,禁止指令重排序
    2. 写操作后加入写屏障,将工作内存中的变量刷新到主内存
    3. 读操作前加入读屏障,从主内存中读取最新的变量值
  • 不能保证原子性:volatile 只能保证可见性和有序性,不能保证原子性。例如count++操作包含读取 - 修改 - 写入三个步骤,volatile 无法保证这三个步骤的原子性
  • 适用场景
    1. 状态标记(如 boolean flag)
    2. 双重检查锁定(DCL)实现单例模式
    3. 读写锁的读锁

第 3 周:MySQL 数据库

1. 为什么 MySQL 用 B + 树作为索引结构?⭐

标准答案

  • B + 树特点
    1. 所有数据都存储在叶子节点,非叶子节点只存储索引
    2. 叶子节点之间用双向链表连接,便于范围查询
    3. 树高更低,一般 3-4 层就能存储千万级数据
  • 与其他结构对比
    1. 二叉树:树高太高,IO 次数多
    2. B 树:非叶子节点也存储数据,每个节点存储的索引少,树高更高
    3. 哈希表:不支持范围查询和排序
  • 项目经验:在设计订单表时,将创建时间作为聚簇索引,提高范围查询的性能
2. 索引失效的常见场景有哪些?⭐

标准答案

  • 对索引列使用函数、表达式或运算
  • 使用不等于(!=、<>)、not in、is not null
  • 字符串不加引号导致隐式类型转换
  • 联合索引不满足最左前缀原则
  • 使用 or 连接包含非索引列的条件
  • like 以 % 开头的模糊查询
  • MySQL 优化器认为全表扫描比索引查询更快
  • 项目经验:在优化慢查询时,发现一个 SQL 因为隐式类型转换导致索引失效,修改后查询时间从 2 秒降低到 10ms
3. MVCC 的实现原理?⭐

标准答案

  • 核心定义:多版本并发控制,通过保存数据的多个版本来实现读写分离,读不加锁,读写不冲突
  • 实现基础
    1. 隐藏字段:每个行记录包含 DB_TRX_ID(事务 ID)、DB_ROLL_PTR(回滚指针)、DB_ROW_ID(行 ID)
    2. undo log:保存数据的历史版本,用于回滚和 MVCC
    3. read view:事务启动时生成的一致性视图,决定能看到哪些版本的数据
  • 可见性规则
    1. 版本的事务 ID < 活跃事务的最小 ID,可见
    2. 版本的事务 ID > 活跃事务的最大 ID,不可见
    3. 版本的事务 ID 在活跃事务范围内,不可见
  • 隔离级别
    1. 读未提交:直接读取最新版本,不使用 MVCC
    2. 读已提交:每次查询生成一个 read view
    3. 可重复读:事务启动时生成一个 read view
    4. 串行化:完全加锁,不使用 MVCC
4. 事务的隔离级别有哪些?分别解决什么问题?

标准答案

隔离级别 脏读 不可重复读 幻读
读未提交
读已提交
可重复读(默认) ✅(MySQL 通过间隙锁解决)
串行化
  • 问题定义
    1. 脏读:一个事务读取了另一个事务未提交的数据
    2. 不可重复读:一个事务内两次读取同一数据,结果不同
    3. 幻读:一个事务内两次查询同一范围,结果行数不同
  • 项目经验:在金融系统中使用串行化隔离级别保证数据一致性,在电商系统中使用默认的可重复读隔离级别
5. 分库分表的方案有哪些?如何选择?

标准答案

  • 水平分表:将一个表的数据按某个字段(如用户 ID)拆分到多个表中
    • 优点:单表数据量小,查询性能高
    • 缺点:跨表查询复杂,事务问题
  • 垂直分表:将一个表的字段拆分到多个表中
    • 优点:减少行大小,提高查询性能
    • 缺点:需要 join 查询
  • 水平分库:将一个库的数据按某个字段拆分到多个库中
    • 优点:解决单库性能瓶颈
    • 缺点:跨库事务复杂
  • 垂直分库:将不同业务的表拆分到不同的库中
    • 优点:业务解耦,便于维护
    • 缺点:跨库 join 复杂
  • 选择原则
    1. 先垂直分库,再水平分表
    2. 优先考虑读写分离和缓存,最后考虑分库分表
    3. 选择合适的分片键,尽量避免跨分片查询

第 4 周:Spring 全家桶基础

1. Spring Bean 的生命周期?⭐

标准答案

  • 实例化:调用构造方法创建 Bean 实例
  • 属性赋值:注入依赖的属性
  • 初始化
    1. 执行 Aware 接口的方法(BeanNameAware、BeanFactoryAware 等)
    2. 执行 BeanPostProcessor 的 postProcessBeforeInitialization 方法
    3. 执行 @PostConstruct 注解的方法
    4. 执行 InitializingBean 的 afterPropertiesSet 方法
    5. 执行 init-method 指定的方法
    6. 执行 BeanPostProcessor 的 postProcessAfterInitialization 方法
  • 使用:Bean 可以被应用程序使用
  • 销毁
    1. 执行 @PreDestroy 注解的方法
    2. 执行 DisposableBean 的 destroy 方法
    3. 执行 destroy-method 指定的方法
  • 项目经验:在 Bean 初始化时加载配置文件,在销毁时释放资源
2. Spring 事务的传播机制有哪些?什么场景下事务会失效?⭐

标准答案

  • 传播机制
    1. REQUIRED(默认):如果当前有事务,加入当前事务;如果没有,创建新事务
    2. REQUIRES_NEW:创建新事务,如果当前有事务,挂起当前事务
    3. SUPPORTS:如果当前有事务,加入当前事务;如果没有,以非事务方式执行
    4. NOT_SUPPORTED:以非事务方式执行,如果当前有事务,挂起当前事务
    5. MANDATORY:必须在事务中执行,否则抛出异常
    6. NEVER:必须以非事务方式执行,否则抛出异常
    7. NESTED:如果当前有事务,在嵌套事务中执行;如果没有,创建新事务
  • 事务失效场景
    1. 方法不是 public 的
    2. 自调用(同一个类中方法调用)
    3. 异常被 catch 住没有抛出
    4. 抛出的异常不是 RuntimeException 或 Error
    5. 数据库引擎不支持事务(如 MyISAM)
    6. 多线程环境下
  • 项目经验:在订单支付系统中使用 REQUIRES_NEW 传播机制,保证日志记录事务独立于主事务
3. Spring Boot 自动配置原理?⭐

标准答案

  • 核心注解@SpringBootApplication包含三个注解:
    1. @SpringBootConfiguration:标记为配置类
    2. @EnableAutoConfiguration:开启自动配置
    3. @ComponentScan:扫描指定包下的组件
  • 自动配置流程
    1. Spring Boot 启动时,从 classpath 下的 META-INF/spring.factories 文件中加载所有自动配置类
    2. 根据条件注解(@ConditionalOnClass、@ConditionalOnBean、@ConditionalOnProperty 等)判断是否需要自动配置
    3. 如果满足条件,创建对应的 Bean 并注入到 Spring 容器中
  • 自定义 Starter
    1. 创建自动配置类
    2. 在 META-INF/spring.factories 文件中注册自动配置类
    3. 打包成 jar 包供其他项目使用
  • 项目经验:开发了一个自定义的 Redis Starter,简化了 Redis 的配置和使用
4. Spring AOP 的实现原理?

标准答案

  • 核心概念
    1. 切面(Aspect):横切关注点的模块化
    2. 连接点(JoinPoint):程序执行的某个点
    3. 通知(Advice):在连接点执行的动作
    4. 切入点(Pointcut):匹配连接点的表达式
  • 实现原理
    1. JDK 动态代理:基于接口实现,只能代理实现了接口的类
    2. CGLIB 动态代理:基于继承实现,可以代理没有实现接口的类
  • Spring AOP 默认选择
    1. 如果目标对象实现了接口,使用 JDK 动态代理
    2. 如果目标对象没有实现接口,使用 CGLIB 动态代理
  • 项目经验:使用 AOP 实现了系统的日志记录、权限控制和性能监控
5. MyBatis 一级缓存和二级缓存的区别?

标准答案

特性 一级缓存 二级缓存
作用范围 SqlSession 级别 Mapper 级别
默认开启
实现方式 HashMap HashMap
共享范围 同一个 SqlSession 多个 SqlSession
失效时机 SqlSession 关闭、提交、回滚、执行更新操作 执行更新操作
  • 注意事项
    1. 一级缓存只在同一个 SqlSession 中有效,跨 SqlSession 会失效
    2. 二级缓存可能导致脏读问题,不建议使用
    3. 分布式环境下不要使用二级缓存,改用 Redis 等分布式缓存
  • 项目经验:在项目中关闭了二级缓存,使用 Redis 作为分布式缓存

第二阶段:进阶提升期(第 5-8 周)

第 5 周:Redis 缓存中间件

1. Redis 的五大数据结构及底层实现?⭐

标准答案

  • String:简单动态字符串(SDS),比 C 语言字符串更安全、高效
  • List:双向链表 + 压缩列表,元素少时用压缩列表,元素多时用双向链表
  • Hash:压缩列表 + 哈希表,元素少时用压缩列表,元素多时用哈希表
  • Set:整数集合 + 哈希表,元素都是整数且数量少时用整数集合,否则用哈希表
  • ZSet:压缩列表 + 跳表,元素少时用压缩列表,元素多时用跳表
  • 项目经验:使用 String 实现分布式锁,使用 Hash 存储用户信息,使用 ZSet 实现排行榜
2. Redis 持久化机制 RDB 和 AOF 的区别?⭐

标准答案

特性 RDB AOF
保存方式 保存某个时间点的全量数据快照 保存所有写命令
恢复速度
数据完整性 差,可能丢失最后一次快照后的数据 好,最多丢失 1 秒数据
文件大小
性能影响 大,fork 子进程会阻塞主线程 小,写命令异步写入磁盘
  • 混合持久化:Redis4.0 + 支持,先写 RDB 快照,再写 AOF 日志,结合了两者的优点
  • 项目经验:在生产环境中使用混合持久化,既保证了数据完整性,又提高了恢复速度
3. 如何解决缓存穿透、缓存击穿、缓存雪崩问题?⭐

标准答案

  • 缓存穿透:查询不存在的数据,请求直接打到数据库
    • 解决方案:
      1. 布隆过滤器:将所有存在的 key 存入布隆过滤器,查询前先过滤
      2. 缓存空值:将不存在的 key 缓存为空值,设置较短的过期时间
  • 缓存击穿:热点 key 过期,大量请求同时打到数据库
    • 解决方案:
      1. 互斥锁:只允许一个请求查询数据库并更新缓存
      2. 热点 key 永不过期
      3. 提前预热热点 key
  • 缓存雪崩:大量 key 同时过期,大量请求同时打到数据库
    • 解决方案:
      1. 过期时间加随机值,避免同时过期
      2. 集群部署,将热点 key 分散到不同节点
      3. 熔断降级,保护数据库
  • 项目经验:在电商大促前,提前预热所有商品的缓存,将过期时间设置为 1 小时 + 随机 10 分钟,避免缓存雪崩
4. Redis 分布式锁的实现?有什么问题?如何解决?

标准答案

  • 基本实现
    String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
    if ("OK".equals(result)) {
        // 获取锁成功
        try {
            // 执行业务逻辑
        } finally {
            // 释放锁
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        }
    }
    
  • 存在的问题
    1. 锁过期时间设置不合理,业务逻辑还没执行完锁就过期了
    2. 主从切换导致锁丢失
  • 解决方案
    1. 看门狗机制:Redisson 的看门狗会在锁过期前自动续期
    2. RedLock 算法:向多个 Redis 节点申请锁,大多数节点成功才算获取锁成功
  • 项目经验:在订单支付系统中使用 Redisson 分布式锁,保证同一订单只能被一个线程处理
5. Redis Cluster 集群的工作原理?

标准答案

  • 数据分片:将整个数据集划分为 16384 个哈希槽,每个节点负责一部分哈希槽
  • 数据路由:客户端计算 key 的哈希值,对 16384 取模得到对应的哈希槽,然后直接访问负责该哈希槽的节点
  • 主从复制:每个主节点可以有多个从节点,主节点负责写操作,从节点负责读操作
  • 故障转移:当主节点故障时,集群会自动选举一个从节点作为新的主节点
  • 项目经验:搭建了一个 3 主 3 从的 Redis Cluster 集群,支撑了每秒 10 万 + 的读写请求

第 6 周:消息队列与分布式基础

1. Kafka 的架构设计和 ISR 机制?⭐

标准答案

  • 核心组件
    1. Producer:生产者,发送消息到 Broker
    2. Broker:Kafka 服务器,存储消息
    3. Topic:消息主题,消息的分类
    4. Partition:分区,Topic 的子集,每个分区是一个有序的队列
    5. Consumer:消费者,从 Broker 拉取消息
    6. Consumer Group:消费者组,多个消费者组成一个组,共同消费一个 Topic
  • ISR 机制
    1. ISR(In-Sync Replicas)是与主副本保持同步的副本集合
    2. 只有 ISR 中的副本才有资格被选举为新的主副本
    3. 当生产者发送消息时,只有当 ISR 中的所有副本都确认收到消息,消息才被认为是已提交
  • 优势:高吞吐量、低延迟、高可用、可扩展
  • 项目经验:在电商订单系统中使用 Kafka 实现异步下单,将下单接口的响应时间从 200ms 降低到 50ms
2. Kafka 如何保证消息的可靠性?

标准答案

  • 生产者端
    1. acks 参数:
      • acks=0:生产者不等待 Broker 确认,性能最高,可靠性最低
      • acks=1:生产者等待主副本确认,性能中等,可靠性中等
      • acks=all/-1:生产者等待 ISR 中所有副本确认,性能最低,可靠性最高
    2. 重试机制:设置 retries 参数,发送失败时自动重试
    3. 幂等性:设置 enable.idempotence=true,保证消息不会重复发送
  • Broker 端
    1. 副本机制:每个分区有多个副本,保证数据不丢失
    2. ISR 机制:保证只有同步的副本才能被选举为主副本
  • 消费者端
    1. 手动提交 offset:处理完消息后再提交 offset,保证消息至少被消费一次
    2. 幂等性处理:消费者端保证消息不会被重复处理
  • 项目经验:在支付系统中设置 acks=all,手动提交 offset,保证消息的可靠性
3. 分布式事务的解决方案有哪些?各自的优缺点?⭐

标准答案

方案 原理 优点 缺点 适用场景
2PC(两阶段提交) 准备阶段 + 提交阶段 强一致性 性能差,单点故障,阻塞 传统数据库事务
3PC(三阶段提交) 准备阶段 + 预提交阶段 + 提交阶段 减少阻塞 性能差,仍有数据不一致问题 很少使用
TCC(补偿事务) Try-Confirm-Cancel 性能好,灵活性高 开发成本高,需要编写补偿逻辑 核心业务,对一致性要求高
SAGA 长事务拆分为多个短事务,通过事件驱动 性能好,无锁 一致性弱,需要处理补偿和回滚 长事务,对一致性要求不高
本地消息表 本地事务 + 消息队列 实现简单,性能好 消息表与业务表耦合 非核心业务,对一致性要求不高
最大努力通知 消息队列反复通知,直到成功 实现简单 一致性最弱 通知类业务
  • 项目经验:在订单支付系统中使用 Seata 的 TCC 模式实现分布式事务,保证订单和支付数据的一致性
4. CAP 定理和 BASE 理论?

标准答案

  • CAP 定理:分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)三者不可兼得,只能同时满足两个
    1. CP:保证一致性和分区容错性,牺牲可用性,如 ZooKeeper
    2. AP:保证可用性和分区容错性,牺牲一致性,如 Eureka
  • BASE 理论:CAP 定理的延伸,是对大型互联网分布式系统的总结
    1. Basically Available(基本可用):系统出现故障时,允许损失部分可用性
    2. Soft State(软状态):允许系统存在中间状态,该状态不影响系统的整体可用性
    3. Eventually Consistent(最终一致性):系统中的所有数据副本经过一段时间后,最终能够达到一致的状态
  • 项目经验:在电商系统中采用 AP 架构,保证系统的高可用性,通过最终一致性保证数据的一致性
5. ZooKeeper 的分布式锁实现原理?

标准答案

  • 实现原理
    1. 客户端在 ZooKeeper 的某个节点下创建临时顺序节点
    2. 客户端获取该节点下的所有子节点,判断自己的节点是否是序号最小的
    3. 如果是,获取锁成功;如果不是,监听前一个节点的删除事件
    4. 当前一个节点被删除时,客户端收到通知,再次判断自己的节点是否是序号最小的
    5. 释放锁时,删除自己创建的临时节点
  • 优势
    1. 避免惊群效应,每个节点只监听前一个节点
    2. 临时节点自动释放锁,避免死锁
  • 缺点
    1. 性能不如 Redis 分布式锁
    2. 网络抖动可能导致临时节点被删除,锁被误释放
  • 项目经验:在配置中心系统中使用 ZooKeeper 分布式锁,保证配置更新的原子性

第 7 周:微服务与云原生

1. 微服务的设计原则和服务拆分方法?⭐

标准答案

  • 设计原则
    1. 单一职责:每个服务只负责一个业务领域
    2. 自治:服务独立开发、部署、运行、扩展
    3. 去中心化:数据去中心化,技术去中心化
    4. 容错设计:服务故障不会导致整个系统崩溃
    5. 演进式设计:服务可以随着业务的发展不断演进
  • 服务拆分方法
    1. 按业务领域拆分:根据 DDD 的限界上下文拆分,是最常用的方法
    2. 按功能拆分:将系统的不同功能拆分为不同的服务
    3. 按数据拆分:将不同的数据实体拆分为不同的服务
  • 拆分粒度
    1. 太粗:服务内部耦合度高,难以维护
    2. 太细:服务间调用复杂,性能差
    3. 最佳实践:先粗后细,随着业务的发展不断调整
  • 项目经验:将电商系统拆分为用户服务、商品服务、订单服务、支付服务、物流服务等
2. Spring Cloud Gateway 的工作原理?

标准答案

  • 核心组件
    1. Route(路由):网关的基本构建块,由 ID、目标 URI、断言集合和过滤器集合组成
    2. Predicate(断言):匹配 HTTP 请求的条件,如路径、方法、头信息等
    3. Filter(过滤器):对请求和响应进行修改,分为全局过滤器和局部过滤器
  • 工作流程
    1. 客户端发送请求到网关
    2. 网关通过断言匹配路由
    3. 路由匹配成功后,经过过滤器链处理请求
    4. 请求转发到目标服务
    5. 目标服务返回响应,经过过滤器链处理后返回给客户端
  • 优势
    1. 基于 Spring 5、Spring Boot 2 和 Reactor,非阻塞异步
    2. 支持动态路由、熔断降级、限流、负载均衡
    3. 与 Spring Cloud 生态无缝集成
  • 项目经验:使用 Spring Cloud Gateway 实现了系统的统一入口、认证授权、限流熔断
3. Nacos 的服务注册发现和配置中心原理?

标准答案

  • 服务注册发现
    1. 服务启动时,向 Nacos 注册自己的信息(IP、端口、服务名等)
    2. Nacos 将服务信息存储在内存中
    3. 消费者从 Nacos 获取服务列表
    4. Nacos 通过心跳机制检测服务的健康状态,不健康的服务会被剔除
  • 配置中心
    1. 配置信息存储在 Nacos 的数据库中
    2. 客户端启动时,从 Nacos 拉取配置信息
    3. 当配置信息发生变化时,Nacos 会主动推送变化给客户端
    4. 客户端更新本地配置
  • 优势
    1. 同时支持服务注册发现和配置中心
    2. 支持 AP 和 CP 模式切换
    3. 界面友好,易于管理
  • 项目经验:使用 Nacos 作为服务注册发现和配置中心,简化了微服务的配置和管理
4. Sentinel 的熔断降级和限流原理?

标准答案

  • 限流原理
    1. 统计请求的 QPS、线程数等指标
    2. 当指标达到阈值时,触发限流
    3. 限流策略:直接拒绝、Warm Up、匀速排队
  • 熔断降级原理
    1. 统计请求的异常比例、异常数、响应时间等指标
    2. 当指标达到阈值时,触发熔断
    3. 熔断状态:
      • 打开:所有请求都被拒绝
      • 半开:允许部分请求通过,测试服务是否恢复
      • 关闭:所有请求都正常通过
  • 优势
    1. 轻量级,性能好
    2. 支持多种限流熔断策略
    3. 实时监控,易于管理
  • 项目经验:在电商大促时,使用 Sentinel 对非核心服务进行限流降级,保证核心服务的可用性
5. Docker 和 Kubernetes 的核心概念?

标准答案

  • Docker 核心概念
    1. 镜像(Image):只读模板,用于创建容器
    2. 容器(Container):镜像的运行实例,是一个独立的运行环境
    3. 仓库(Repository):存储镜像的地方
  • Kubernetes 核心概念
    1. Pod:最小的部署单元,包含一个或多个容器
    2. Deployment:管理 Pod 的创建、更新、删除
    3. Service:为 Pod 提供统一的访问入口
    4. ConfigMap:存储配置信息
    5. Secret:存储敏感信息
    6. Namespace:用于隔离不同的环境
  • 项目经验:使用 Docker 将应用容器化,使用 Kubernetes 部署和管理微服务应用

第 8 周:系统设计与项目准备

1. 设计一个短链接系统

标准答案

  • 核心需求
    1. 将长链接转换为短链接
    2. 访问短链接时重定向到长链接
    3. 支持自定义短链接
    4. 支持统计访问量
  • 系统架构
    1. 前端:用户输入长链接,生成短链接
    2. 后端
      • 生成短链接:使用哈希算法(如 MD5)将长链接转换为 62 进制字符串
      • 重定向:根据短链接查询长链接,返回 302 重定向
    3. 数据库:存储短链接和长链接的映射关系
    4. 缓存:使用 Redis 缓存热门短链接,提高查询性能
  • 关键问题
    1. 哈希冲突:使用自增 ID+62 进制编码的方式生成短链接,避免哈希冲突
    2. 性能优化:使用缓存、读写分离、分库分表提高系统性能
    3. 安全性:防止恶意生成短链接,限制生成频率
2. 设计一个秒杀系统

标准答案

  • 核心需求
    1. 商品库存有限,先到先得
    2. 高并发,每秒数万甚至数十万请求
    3. 防止超卖
    4. 防止恶意刷单
  • 系统架构
    1. 前端
      • 页面静态化,将商品详情页静态化到 CDN
      • 按钮置灰,防止重复提交
      • 验证码,防止机器刷单
    2. 后端
      • 限流:使用 Sentinel 对接口进行限流
      • 削峰:使用消息队列将请求异步化
      • 库存扣减:使用 Redis 预扣减库存,数据库最终扣减
      • 订单处理:异步处理订单,提高系统吞吐量
    3. 数据库
      • 分库分表,提高数据库性能
      • 乐观锁,防止超卖
  • 关键问题
    1. 超卖问题:使用 Redis 原子操作扣减库存,数据库乐观锁保证最终一致性
    2. 高并发问题:使用缓存、异步、限流、削峰等技术提高系统性能
    3. 恶意刷单问题:使用验证码、IP 限制、用户限制等方式防止恶意刷单
3. 分布式 ID 生成方案有哪些?如何选择?

标准答案

方案 原理 优点 缺点 适用场景
UUID 128 位随机数 实现简单,无单点故障 无序,占用空间大,查询性能差 非主键,不需要排序
数据库自增 ID 数据库自增主键 实现简单,有序 单点故障,性能差,分库分表复杂 单库单表,并发量小
号段模式 从数据库批量获取 ID 段,在内存中分配 性能好,有序 有单点故障,需要处理号段耗尽问题 大部分业务场景
雪花算法(Snowflake) 64 位 ID,包含时间戳、机器 ID、序列号 性能好,有序,无单点故障 时钟回拨问题 分布式系统,高并发
  • 项目经验:在电商系统中使用雪花算法生成订单 ID,解决了分库分表后的 ID 生成问题
4. 设计一个 AI 接口调用方案

标准答案

  • 核心需求
    1. 调用 AI 接口生成内容
    2. 保证接口延迟可控
    3. 防止 AI 接口过载
    4. 支持重试和降级
  • 系统架构
    1. API 网关:统一入口,认证授权,限流熔断
    2. AI 服务:封装 AI 接口,提供统一的调用方式
    3. 缓存:缓存常用的 AI 生成结果,提高响应速度
    4. 消息队列:异步处理非实时的 AI 请求
    5. 监控告警:监控 AI 接口的调用情况,异常时告警
  • 关键问题
    1. 延迟问题
      • 使用缓存,避免重复调用 AI 接口
      • 异步处理非实时请求
      • 设置超时时间,避免长时间等待
    2. 过载问题
      • 使用限流,限制 AI 接口的调用频率
      • 使用降级,当 AI 接口不可用时返回默认内容
    3. 可靠性问题
      • 使用重试机制,调用失败时自动重试
      • 使用消息队列,保证消息不丢失
5. 如何用 STAR 法则介绍项目?

标准答案

  • S(Situation):项目背景,为什么要做这个项目,面临什么问题
  • T(Task):你的任务和职责,你负责什么工作
  • A(Action):你采取了什么行动,具体做了什么,用了什么技术
  • R(Result):取得了什么成果,最好有量化的数据
  • 示例

    S:电商大促时,订单系统的响应时间从 50ms 增加到 500ms,严重影响用户体验 T:我负责优化订单系统的性能,将响应时间降低到 100ms 以内 A:我首先使用 Arthas 监控系统的性能瓶颈,发现是数据库查询慢导致的。然后我做了以下优化:1. 给订单表添加了合适的索引;2. 使用 Redis 缓存了热门订单;3. 将订单查询和订单创建分离,使用读写分离;4. 优化了 SQL 语句,避免了全表扫描 R:优化后,订单系统的响应时间降低到 80ms,大促期间系统稳定运行,没有出现性能问题,订单处理能力提高了 5 倍

第三阶段:冲刺模拟期(第 9-12 周)

算法高频题(LeetCode 中等难度)

  1. 数组:两数之和、三数之和、最大子数组和、乘积最大子数组
  2. 字符串:最长回文子串、最长公共前缀、字符串反转、字符串匹配
  3. 链表:反转链表、合并两个有序链表、环形链表、删除链表的倒数第 N 个节点
  4. :二叉树的前中后序遍历、层序遍历、二叉树的最大深度、验证二叉搜索树
  5. 动态规划:爬楼梯、斐波那契数列、最长递增子序列、最长公共子序列、背包问题
  6. 二分查找:搜索插入位置、在排序数组中查找元素的第一个和最后一个位置、搜索旋转排序数组
  7. 栈和队列:有效的括号、最小栈、用栈实现队列、滑动窗口最大值

面试常见非技术问题

  1. 请做一个自我介绍
  2. 你为什么想离开现在的公司?
  3. 你为什么想来我们公司?
  4. 你的职业规划是什么?
  5. 你最大的优点和缺点是什么?
  6. 你遇到过的最大的挑战是什么?你是怎么解决的?
  7. 你平时是怎么学习新技术的?
  8. 你有什么问题要问我吗?

220万字精选面试题

需要的同学直接查看下方名片!!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐