Java场景面试宝典
文章标题
《大厂面试连环炮:从八股文到AI Agent,小明是如何被面试官“KO”的?》
文章内容
第一轮:Java核心 + JUC + JVM(地基题)
面试官(严肃脸):
“先热个身。说说HashMap的put流程,以及1.7和1.8的区别。”
小明(得意):
“这简单!put的时候先算hash,然后找数组下标。1.7是头插法,1.8改成尾插法,还加了红黑树优化。如果有hash冲突,链表长度超过8就转红黑树。面试官,我答得怎么样?”
面试官(点头):
“不错,基础扎实。那么,JUC包下面,说说ConcurrentHashMap在1.8是怎么保证线程安全的?还有,ArrayBlockingQueue和LinkedBlockingQueue的区别是什么?”
小明(信心倍增):
“1.8的ConcurrentHashMap用synchronized + CAS实现,每个节点都锁住,效率高。ArrayBlockingQueue是数组实现的有界队列,LinkedBlockingQueue是链表实现,默认无界——实际上也可以设边界。”
面试官(追问):
“那你再聊聊JVM内存模型。比如GC Roots有哪些?CMS和G1有什么区别?”
小明(有点慌了):
“GC Roots...呃,就是那些栈帧里的局部变量、静态变量什么的。CMS是并发标记清除,G1是分区域回收,具体算法我忘了。不过G1能预测停顿时间,CMS容易产生碎片。”
(内心OS:别问了别问了……)
第二轮:Spring全家桶 + 中间件(实战题)
面试官(微笑):
“项目里用了SpringBoot,说说自动装配的原理。还有,Spring事务在什么情况下会失效?”
小明(松了一口气):
“自动装配?就是那个@SpringBootApplication注解,里面有@EnableAutoConfiguration,会加载spring.factories里的配置类。事务失效嘛,比如调用本类方法、没加@Transactional、异常没捕获等等。”
面试官(不紧不慢):
“那么,MyBatis里的#{}和${}有什么区别?一级缓存和二级缓存知道吗?”
小明(开始飘了):
“#{}是预编译,防止SQL注入;${}是直接拼接,不能乱用。一级缓存是SqlSession级别的,默认开启;二级缓存需要手动开启,跨session共享。”
面试官(眼睛一亮):
“那你用过Dubbo的集群容错策略吗?RabbitMQ如何保证消息不丢失?”
小明(支支吾吾):
“Dubbo有Failover、Failfast那些……RabbitMQ要开启持久化,生产者用confirm模式,消费者手动ack……具体怎么配我忘了,但大致是这样。”
(面试官:好一个‘大致’。)
第三轮:高难度核弹——Redis + 设计模式 + AI Agent + DDD(送命题)
面试官(拿出杀手锏):
“Redis的分布式锁怎么实现?RedLock知道吗?还有,MySQL的MVCC机制,讲讲Read View的生成规则。”
小明(额头冒汗):
“分布式锁可以用SETNX,配合Lua脚本。RedLock是多个Redis实例的算法,保证强一致性。MVCC……就是多版本并发控制,Read View根据活跃事务列表判断当前事务能看到哪个版本。”
(其实已经快背不下去了。)
面试官(继续加压):
“设计模式里,策略模式和状态模式有什么区别?DDD里的聚合根、值对象怎么划分?”
小明(彻底破防):
“策略模式是行为可以替换,状态模式是状态改变行为。聚合根就是有全局唯一ID的实体,值对象没ID,不可变……比如地址。”
(明显开始胡说了。)
面试官(嘴角上扬):
“最后考你个前沿的。Spring AI集成大模型时,MCP协议和RAG模式有什么区别?AI Agent里function call是怎么实现的?”
小明(大脑宕机):
“啊这……MCP是模型上下文协议,能让大模型调用外部工具?RAG是检索增强生成,就是先查数据库再生成答案。AI Agent的function call……就是告诉模型有哪些函数可用,模型自己选择调用,具体实现我还没写过。”
(内心:完了,这个我真不会。)
面试官(合上笔记本):
“嗯,今天先到这里。技术广度还可以,深度和实战需要再积累。你先回去等通知吧。”
小明(欲哭无泪):
“好的,谢谢面试官……”
(OS:下次一定好好学!)
文章标签
Java面试, JUC, JVM, SpringBoot, MyBatis, Redis, RabbitMQ, Dubbo, 设计模式, DDD, AI Agent, MCP, RAG, 八股文, 搞笑面试
文章简述
一位严肃的大厂面试官与“水货”程序员小明上演了一场从基础八股到AI前沿的连环炮面试。三轮提问层层递进:从HashMap、JVM内存模型,到Spring事务、RabbitMQ消息可靠性,再到分布式锁、MVCC、设计模式、DDD,最后“暴击”Spring AI、MCP与RAG。文章后半部分附有详细技术答案,覆盖核心知识点,让小白既能笑出腹肌,又能学到硬核干货。
详细答案(技术点全解析)
第一轮答案
1. HashMap put流程 & 1.7/1.8区别
- put流程:计算key的hash -> (n-1) & hash得到数组下标 -> 如果为空直接放入,否则遍历链表/红黑树 -> 如果已存在则覆盖value,否则插入 -> 检查是否需要扩容(threshold = loadFactor * capacity)。
- 1.7 vs 1.8:
- 1.7:数组+链表,头插法(多线程下环形链表风险),扩容时Rehash,所有元素重新计算索引。
- 1.8:数组+链表+红黑树,尾插法,扩容时链表保持原序(通过高低位拆分),链表长度>=8且数组长度>=64转为红黑树。
2. ConcurrentHashMap 1.8 线程安全机制
- 采用 synchronized + CAS 实现线程安全。put时先CAS更新数组元素(如头结点为空),遇到hash冲突则对链表头结点加synchronized锁。扩容时通过多个线程协同(transfer)提高效率。
- 相比1.7的Segment分段锁,1.8粒度更细(每个数组元素一个锁),并发度更高。
3. ArrayBlockingQueue vs LinkedBlockingQueue
- ArrayBlockingQueue:基于数组,有界,一把全局锁(读写共用),公平/非公平模式。
- LinkedBlockingQueue:基于链表,有界(默认Integer.MAX_VALUE),读写分离两把锁(takeLock + putLock),吞吐量更高。
- 共同点:都实现了BlockingQueue,支持阻塞的put/take。
4. JVM GC Roots & CMS/G1区别
- GC Roots:虚拟机栈引用、静态属性引用、常量引用、本地方法栈引用、活跃线程、synchronized持有的对象等。
- CMS:初始标记(Stop The World)、并发标记、重新标记(STW)、并发清除。优点:低延迟。缺点:浮动垃圾、内存碎片、CPU敏感。
- G1:分Region(Eden/Survivor/Old/Humongous),通过预测停顿时间模型,优先回收收益最大的Region。采用SATB(原始快照)解决并发标记问题。
第二轮答案
1. SpringBoot自动装配原理
@SpringBootApplication包含@EnableAutoConfiguration-> 导入AutoConfigurationImportSelector-> 加载所有META-INF/spring.factories中的自动配置类 -> 通过@ConditionalOnClass、@ConditionalOnMissingBean等条件判断是否启用。
2. Spring事务失效场景
- 数据库引擎不支持事务(如MyISAM)。
- 注解的方法不是public。
- 自调用:同类中方法内部调用带@Transactional的方法,不走代理。
- 异常被捕获未抛出(需配置rollbackFor)。
- 传播行为设置错误(如PROPAGATION_NOT_SUPPORTED)。
3. MyBatis #{} vs ${}
#{}:预编译,生成?占位符,防止SQL注入。${}:直接字符串替换,存在注入风险,用于动态表名/列名。
4. MyBatis一级/二级缓存
- 一级缓存:SqlSession级别,默认开启,同一次会话中查询相同SQL返回缓存对象。
- 二级缓存:Mapper级别(跨SqlSession),需在xml中配置
<cache/>,默认使用PerpetualCache;注意脏读问题,需开启cache-ref或使用第三方缓存如Redis。
5. Dubbo集群容错策略
- Failover(默认):失败自动切换(重试其他服务器)。
- Failfast:快速失败,只调用一次,失败立即报错。
- Failsafe:失败安全,忽略异常。
- Failback:失败自动恢复,后台记录失败请求并重试。
- Forking:并行调用多个服务,只要一个成功就返回。
6. RabbitMQ消息不丢失
- 生产者确认:开启Confirm模式(publisher-confirm-type: correlated),确认回调;配合ReturnCallback处理路由不到的消息。
- 消息持久化:队列durable=true,消息deliveryMode=2。
- 消费者手动ack:
basicAck确认处理成功,basicNack拒绝或重新入队。 - 镜像队列:解决单点故障。
第三轮答案
1. Redis分布式锁 & RedLock
- SETNX + Lua:
SET key value NX EX 30原子操作,释放时用Lua脚本比较value再删除(防止误删)。 - RedLock:客户端获取当前时间 -> 依次向N个(通常5个)Redis节点请求锁(超时时间短) -> 如果半数以上成功且总耗时 < 锁有效时间,则加锁成功。释放时向所有节点发送DEL。解决单点故障,但需保证时钟漂移。
2. MVCC & Read View生成规则
- MVCC:通过undo log实现多版本并发控制,每个事务拥有事务ID(trx_id)。
- Read View:由
m_ids(活跃事务ID列表)、low_limit_id(未分配最小事务ID)、up_limit_id(最小活跃事务ID)、creator_trx_id(当前事务ID)组成。 - 可见性判断:
- 数据行trx_id == creator_trx_id → 可见(自己修改的)。
- 数据行trx_id < up_limit_id → 可见(已提交)。
- 数据行trx_id ≥ low_limit_id → 不可见(未来事务)。
- 在m_ids中且trx_id ≠ creator_trx_id → 不可见(活跃事务未提交)。
3. 策略模式 vs 状态模式
- 策略模式:算法族封装,客户端选择策略,行为可互换(如支付方式)。核心:算法独立于客户端。
- 状态模式:对象内部状态改变导致行为改变,状态转换由Context管理(如订单状态机)。核心:行为跟随状态变化。
4. DDD 聚合根 & 值对象
- 聚合根:是聚合的入口,拥有全局唯一标识(ID),负责维护聚合内部一致性(如订单Order)。外部只能通过聚合根操作聚合内的实体。
- 值对象:没有唯一标识,描述某个方面的属性,不可变(如地址Address)。可被聚合根引用来描述特征。
5. Spring AI & MCP & RAG
- Spring AI:简化AI集成,提供ChatClient、EmbeddingClient、VectorStore等抽象,支持OpenAI、通义千问等模型。
- MCP(Model Context Protocol):一种开放协议,允许AI模型通过标准接口调用外部工具(如数据库、API)。模型通过MCP发现工具、执行函数、获取结果,实现与真实世界的交互。
- RAG(Retrieval-Augmented Generation):先向量化文档存入向量数据库(如Pgvector、Milvus),用户提问时检索相关片段拼接到Prompt中,让模型基于检索结果生成答案。优势:解决知识时效性,减少幻觉。
- AI Agent & Function Call:Agent根据用户意图拆分任务,通过大模型function call能力选择工具执行(如调用天气API、查数据库)。Spring AI中通过
@Tool注解定义工具,模型自动决定调用。例如:@Tool("查询订单") public String queryOrder(String orderId),模型分析问题后自动调用并返回结果。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)