大厂 Java 面试实录:面试官狂问技术八股,水货程序员谢飞机能撑几轮?

张开发
2026/4/9 9:14:30 15 分钟阅读

分享文章

大厂 Java 面试实录:面试官狂问技术八股,水货程序员谢飞机能撑几轮?
大厂 Java 面试实录面试官狂问技术八股水货程序员谢飞机能撑几轮一、面试开场周一上午九点某互联网大厂 18 楼 3 号会议室。空气安静得像线上环境刚重启完服务一样可怕。面试官推了推眼镜低头看着简历声音冷静得像 JVM 的 Full GC 日志面试官你好先做个自我介绍吧。谢飞机坐得笔直神情庄重像是即将守护整个微服务宇宙谢飞机面试官好我叫谢飞机5 年 Java 开发经验熟悉 Java 基础、JVM、并发编程、Spring 全家桶、MyBatis、Dubbo、Redis、MySQL、MQ、容器化部署也对 DDD 和设计模式有深入理解。面试官抬头看了他一眼。那眼神像在看一个刚把“精通”写满简历的人。面试官好那我们开始。今天一共三轮问题每轮会结合业务场景逐步深入。谢飞机没问题我这人最大的优点就是稳定输出。面试官希望不是日志输出。二、第一轮Java 基础 集合 并发基础问题 1说一下HashMap的底层数据结构以及为什么长度一般是 2 的幂谢飞机HashMap 底层就是数组加链表加红黑树这个我熟。长度是 2 的幂主要是因为程序员都喜欢整齐2、4、8、16 看起来很舒服。面试官眉毛轻轻动了一下。谢飞机当然更重要的是这样算下标比较快可以用位运算比如(n - 1) hash效率很高。如果不是 2 的幂数据分布就容易不均匀。面试官嗯这个回答还可以。谢飞机眼睛一亮仿佛获得了年度最佳员工提名。问题 2ArrayList和LinkedList的区别业务中你怎么选谢飞机ArrayList 底层是数组LinkedList 底层是链表。ArrayList 查得快LinkedList 增删快。面试官只是理论上谢飞机对理论上是这样。实际上如果业务里不是频繁在中间插入而且还要考虑缓存命中、遍历效率、内存占用那基本上大家都用 ArrayList。LinkedList 更多是面试时使用生产里主要负责出现在 PPT 和八股文里。面试官第一次点头。面试官这句很真实。问题 3如果线上有一个订单服务多个线程同时修改库存你怎么保证线程安全谢飞机可以加synchronized或者ReentrantLock。如果是单机就锁代码块如果是分布式就上 Redis 分布式锁。面试官那你说说synchronized和ReentrantLock的区别。谢飞机synchronized是 JVM 帮你管ReentrantLock是 Java 代码自己管。一个比较官方一个比较灵活。ReentrantLock可以手动上锁解锁还能可中断还能尝试获取锁还能配合Condition。如果忘记释放锁就会让同事很难受。面试官回答得不错。谢飞机悄悄挺了挺胸。问题 4线程池的核心参数有哪些为什么不建议直接用Executors创建线程池谢飞机线程池有核心线程数、最大线程数、阻塞队列、线程存活时间、线程工厂、拒绝策略。面试官继续。谢飞机不建议用Executors因为它给你包装好了表面上很贴心实际上可能埋坑。比如FixedThreadPool和SingleThreadExecutor用的是无界队列任务太多可能把内存撑爆CachedThreadPool最大线程数几乎无限容易把机器线程创建到怀疑人生。面试官嗯知道风险点挺好。谢飞机脸上露出了“今天稳了”的笑容。三、第二轮JVM Spring MyBatis 微服务面试官翻了一页简历语气开始进入真正的技术区。面试官下面我们结合一个电商系统场景。假设用户下单后会调用库存服务、优惠券服务、支付服务。我们继续。问题 1说一下 JVM 内存结构和对象创建过程。谢飞机JVM 内存结构有堆、栈、方法区……还有那个程序数数器还有本地方法什么栈。面试官程序计数器。谢飞机对对对就是那个负责计数程序到底数到哪了。对象创建的话先 new然后 JVM 看类加载了没没加载先加载再分配内存初始化零值设置对象头然后执行构造方法。面试官大致还行。那对象一定在堆里吗谢飞机也不一定有时候它身在堆中心在栈上主要看逃逸分析。面试官停顿了两秒。面试官这句话虽然不严谨但比喻得还挺形象。问题 2Spring 的 IOC 和 AOP 是什么项目里你怎么用的谢飞机IOC 就是控制反转本来对象要自己 new现在交给 Spring 容器管理。DI 是依赖注入把对象塞进来。面试官AOP 呢谢飞机AOP 是面向切面编程把日志、事务、权限这种横切逻辑抽出来。比如订单创建方法我不想每个地方都写事务控制、日志记录就交给 AOP 统一处理。面试官Spring 事务失效场景知道吗谢飞机沉默了一下像 CPU 突然被打满。谢飞机知道一些比如方法不是public比如自调用或者异常没抛对或者数据库引擎不支持或者……项目组氛围不好也可能失效。面试官后面那个删掉。问题 3MyBatis 中#和$的区别为什么一般推荐#谢飞机#是预编译占位符$是字符串拼接。一般推荐#因为能防 SQL 注入。面试官那$什么时候用谢飞机像动态表名、动态排序字段这种 SQL 结构位置预编译不好使的时候才会用但必须自己做好白名单校验不然别人一个drop table过来这个月绩效就没了。面试官可以。问题 4Dubbo 的服务调用流程了解吗如果一个服务超时了你会怎么排查谢飞机Dubbo 就是服务提供者启动后注册到注册中心消费者订阅服务地址然后发起远程调用。面试官更细一点。谢飞机更细的话……就是先代理再网络通信再序列化再调用再反序列化。超时排查的话先看是不是网络问题再看是不是数据库慢再看线程池是不是打满再看有没有 Full GC再看看下游服务是不是装死。面试官“装死”这个词虽然不专业但现象描述准确。四、第三轮Redis MySQL MQ Linux/Docker 设计思想面试官把水杯放下进入最后一轮。面试官假设现在有一个秒杀系统高并发抢购要求抗住流量、保证库存正确、异步削峰、方便部署运维。你来设计一下并回答下面的问题。谢飞机表情逐渐凝重像一个准备徒手接住流量洪峰的人。问题 1Redis 在秒杀场景中怎么用如果出现缓存击穿、穿透、雪崩怎么办谢飞机Redis 可以扛热点数据比如商品库存、活动信息先查缓存再查数据库减少 MySQL 压力。面试官三个问题分别说。谢飞机缓存穿透就是查一个根本不存在的数据每次都打到数据库。可以缓存空值或者用布隆过滤器。谢飞机缓存击穿就是某个热点 key 失效了大量请求同时打数据库。可以加互斥锁、热点永不过期、逻辑过期。谢飞机缓存雪崩就是一大片 key 同时失效。可以把过期时间打散做多级缓存服务降级限流。面试官嗯这题回答得不错。谢飞机脸上浮现出一种“原来我真会”的震惊。问题 2MySQL 索引为什么能加快查询联合索引最左前缀原则是什么谢飞机索引像书的目录能帮助快速定位数据。MySQL InnoDB 里的索引底层一般是 B 树适合范围查询和磁盘 IO。面试官联合索引呢谢飞机联合索引比如(a,b,c)查询条件要尽量从左往右用先用 a再用 ab再用 abc。如果跳过 a后面可能就用不上。这个叫最左前缀原则。面试官那where a 1 and c 3呢谢飞机这个……它会努力一下但努力不一定有效。面试官你这回答很有人生哲理。问题 3RabbitMQ 在这个系统里怎么用如何保证消息不丢失、不重复消费谢飞机RabbitMQ 可以做异步下单、削峰填谷。比如用户抢购成功后把下单请求放到 MQ后面订单服务慢慢消费。面试官如何保证可靠性谢飞机生产者要确认消息发送成功交换机和队列要持久化消费者要手动 ACK。至于重复消费可以做幂等比如订单号唯一、业务表去重、消费记录表。面试官延迟关闭未支付订单怎么做谢飞机可以用 TTL 加死信队列或者延迟插件。用户超过支付时间没付款就发消息关闭订单、恢复库存。面试官不错。问题 4你说说 XXL-JOB、Docker、Linux 常用排查命令以及设计模式、DDD 你是怎么理解的谢飞机表情开始逐渐抽象。谢飞机XXL-JOB 就是分布式任务调度平台可以管理定时任务、分片广播、失败重试。适合对账、报表、补偿任务。面试官Docker 呢谢飞机Docker 就是把应用和环境打包成容器部署起来比较统一。我的理解就是“代码搬家但锅碗瓢盆都带上”。面试官Linux 排查线上问题的命令谢飞机top看资源ps -ef看进程netstat或ss看端口tail -f看日志grep查关键字df -h看磁盘free -m看内存。面试官设计模式和 DDD 呢谢飞机设计模式我常用单例、工厂、策略、模板方法。DDD 的话就是把业务拆明白什么领域、实体、值对象、聚合根把代码写得更像业务而不是像一锅乱炖。至于更深入的实践我更偏向在项目推进中灵活理解。面试官翻译一下。谢飞机就是……我知道概念但做得没那么体系化。面试官这个回答终于诚实了。五、面试结束面试官合上简历恢复了最初那种“服务器无波无澜”的表情。面试官今天先到这里。整体看基础题掌握还可以部分中间件和常见场景也有一定了解。面试官但是 JVM、微服务调用细节、事务底层原理、DDD 落地这些方面回答还不够深入复杂问题表达也不够清晰。谢飞机郑重点头。谢飞机我明白我回去就把这些知识补到能倒背如流。面试官好你先回去等通知。谢飞机这个“等通知”是偏积极的等还是偏具有东方含蓄美学的等面试官下一位。谢飞机起身离开会议室背影里透着一丝倔强。也透着一丝“回去立刻打开收藏夹开始补八股”的坚定。六、面试问题详细答案汇总下面把上面提到的核心问题系统梳理一遍帮助小白学习。1. HashMap 底层原理1底层结构JDK 1.8 中HashMap的底层结构是数组链表红黑树当多个 key 经过哈希后落到数组同一个位置就形成链表。 当链表长度超过阈值默认 8且数组容量足够大时链表会转成红黑树提高查询效率。2为什么容量是 2 的幂因为下标计算使用index (n - 1) hash当n是 2 的幂时二进制位会更规整这样可以让哈希值更均匀地分布到数组中用位运算替代取模提高效率3扩容机制当元素个数超过容量 * 负载因子默认 0.75时会触发扩容。 扩容为原来的 2 倍然后重新分配元素位置。2. ArrayList 和 LinkedList 区别ArrayList底层是动态数组支持随机访问get(index)快尾部新增效率高中间插入删除需要移动元素LinkedList底层是双向链表中间插入删除理论上快不支持高效随机访问每个节点需要额外存储前后指针内存开销更大实际选择生产中大多数场景优先使用ArrayList因为遍历效率更高CPU 缓存友好内存占用更低3. synchronized 和 ReentrantLock 区别synchronizedJava 关键字由 JVM 层面实现自动加锁、释放锁使用简单ReentrantLockJUC 包下的锁实现需要手动lock()和unlock()支持可中断锁尝试获取锁tryLock()公平锁/非公平锁多条件变量Condition如何选简单同步场景synchronized需要高级功能ReentrantLock4. 线程池核心参数Java 线程池ThreadPoolExecutor主要参数ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueRunnable workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)参数说明corePoolSize核心线程数maximumPoolSize最大线程数keepAliveTime非核心线程空闲存活时间workQueue任务阻塞队列threadFactory线程工厂handler拒绝策略为什么不推荐 Executors因为默认工厂可能隐藏风险FixedThreadPool无界队列可能 OOMSingleThreadExecutor无界队列可能 OOMCachedThreadPool线程数几乎无限可能创建过多线程导致系统崩溃所以生产环境一般手动创建线程池。5. JVM 内存结构JVM 运行时数据区主要包括程序计数器记录当前线程执行字节码的位置Java 虚拟机栈存放栈帧、局部变量、方法调用信息本地方法栈服务于 Native 方法堆存放对象实例是 GC 主要区域方法区存放类信息、常量、静态变量、JIT 编译代码等对象创建过程类加载检查分配内存初始化零值设置对象头执行构造方法对象一定在堆上吗不一定。JIT 优化中的逃逸分析可能让对象栈上分配标量替换 从而减少堆内存分配和 GC 压力。6. Spring IOC 和 AOPIOCIOC控制反转是把对象的创建和管理交给 Spring 容器而不是业务代码自己new。DIDI依赖注入是 IOC 的实现方式之一把依赖对象注入给目标对象。AOPAOP面向切面编程用于把公共逻辑抽取出来如日志事务权限控制性能监控常见事务失效场景方法不是public同类中自调用异常被吃掉没有触发回滚配置的异常类型不匹配数据库不支持事务没有被 Spring 管理7. MyBatis 中 # 和 $ 的区别#{}预编译占位符自动加引号、转义防止 SQL 注入例如select * from user where id #{id}${}字符串直接拼接有 SQL 注入风险例如select * from user order by ${column}使用建议优先使用#{}。 只有在动态表名、排序字段等不能预编译的 SQL 片段场景下才使用${}并配合白名单校验。8. Dubbo 调用流程一个典型 Dubbo 调用过程服务提供者启动并注册到注册中心如 Nacos、Zookeeper服务消费者订阅服务列表消费者通过代理对象发起调用选择负载均衡策略选中一个提供者进行序列化和网络传输提供者执行本地方法返回结果并反序列化服务超时排查思路看消费者超时时间配置是否合理看提供者接口执行是否过慢看数据库 SQL 是否慢看线程池是否满了看网络延迟看是否发生 Full GC看下游依赖是否有故障9. Redis 缓存三大问题缓存穿透请求的数据数据库和缓存中都不存在大量请求直接打到数据库。解决方案缓存空值布隆过滤器参数校验缓存击穿某个热点 key 突然失效大量并发请求同时访问数据库。解决方案互斥锁热点数据永不过期逻辑过期 后台重建缓存缓存雪崩大量 key 在同一时间失效流量冲击数据库。解决方案过期时间加随机值多级缓存限流、熔断、降级提高 Redis 高可用能力10. MySQL 索引与最左前缀原则为什么索引快InnoDB 使用B 树作为常见索引结构优势高扇出树高度低减少磁盘 IO叶子节点有序适合范围查询联合索引最左前缀原则索引(a, b, c)可以命中的常见情况where a ?where a ? and b ?where a ? and b ? and c ?where a ? and c ?中通常只能稳定利用到a原因是联合索引在底层按最左字段顺序组织。11. RabbitMQ 如何保证消息可靠性防止消息丢失生产者侧开启confirm确认机制开启return回调处理路由失败Broker 侧交换机持久化队列持久化消息持久化消费者侧手动 ACK失败重试死信队列兜底防止重复消费MQ 无法天然完全避免重复需要业务做幂等订单号唯一约束去重表Redis 幂等标记状态机控制12. XXL-JOB 的作用XXL-JOB 是分布式任务调度平台常用于定时任务统一管理失败重试分片广播任务日志查看动态启停任务业务场景每日对账数据同步订单超时处理报表生成补偿任务13. Linux 常用排查命令查看系统资源top htop free -m df -h查看进程ps -ef | grep java jps jstack jmap jstat查看网络netstat -tunlp ss -lnt查看日志tail -f app.log grep ERROR app.log less app.log查看端口占用lsof -i:808014. Docker 基础理解Docker 通过容器技术把应用及其依赖环境一起打包实现一次构建到处运行环境一致快速部署资源隔离常用命令docker ps docker images docker logs -f 容器ID docker exec -it 容器ID /bin/bash docker build -t demo:1.0 . docker run -d -p 8080:8080 demo:1.015. 设计模式常见应用单例模式确保一个类只有一个实例。 常见于配置管理、线程池管理。工厂模式把对象创建逻辑封装起来。 常见于根据不同条件创建不同实现类。策略模式定义一组算法彼此可替换。 常见于支付方式、优惠计算、路由选择。模板方法模式定义流程骨架具体步骤交给子类实现。 常见于导出、校验、业务处理流程。16. DDD 基本理解DDD领域驱动设计是一种复杂业务系统建模思想核心目标是让代码结构更贴近业务结构。常见概念Entity实体有唯一标识如订单、用户Value Object值对象无唯一标识如地址、金额Aggregate聚合一组相关对象的业务边界Aggregate Root聚合根聚合的唯一入口Repository仓储负责聚合的持久化Domain Service领域服务处理不适合放到实体里的领域逻辑什么时候适合 DDD业务复杂规则多状态流转复杂多团队协作DDD 不是必须的如果系统很简单只是普通 CRUD强行上 DDD 反而会增加复杂度。七、总结这场面试看起来像搞笑对话但真实面试中企业最看重的通常是这几件事基础是否扎实Java、集合、并发、JVM框架是否理解原理Spring、MyBatis、Spring Boot是否有中间件实战经验Redis、MQ、Dubbo是否能结合业务场景答题秒杀、库存、异步、定时任务是否具备排查问题能力MySQL、Linux、Docker、线上故障分析如果你也像谢飞机一样简单题还能接住复杂题就开始语言漂移那说明现在最需要做的事情不是焦虑 而是把每个技术点按“是什么、为什么、怎么用、有什么坑、业务里怎么落地”系统梳理一遍。等你下一次进面试间时面试官说“开始吧”你就不会只剩一句我对这些都有深入理解。而是真的能讲出来。

更多文章