得物 Java 开发一面:并发八股、MySQL 索引与 RAG 项目
- 轮次
- 一面
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- ThreadLocal 的使用场景、原理、风险漏洞是什么?
- 线程池线程之间的信息如何传递?
- 除了 ThreadLocal,还有哪些线程安全的变量访问方式?
- synchronized 和 ReentrantLock 的区别是什么?
- synchronized 的实现原理是什么?锁升级过程是怎样的?ReentrantLock 的实现原理?公平锁与非公平锁的区别和实现原理?
- 原子类了解吗?介绍一下。
- MySQL 事务隔离级别有哪些?对应会出现什么问题?
- 幻读在 RR 下是如何尽可能优化的?
- 索引结构介绍一下。
- 为什么使用 B+ 树,不使用二叉树、红黑树、B 树这些?
- ReAct 模式和 Plan and Execute 模式的区别是什么?适用场景分别是什么?
- ReAct 是怎么实现的?是手写的还是用 Spring AI Alibaba 已有的?如果让你自己实现,你的思路是怎样的?
- 逻辑题:时钟上 3:15 时,时针与分针对应的夹角是多少度?
《参考解析》
ThreadLocal 与内存泄漏:每个 Thread 内部有一个 ThreadLocalMap,key 是 ThreadLocal 的弱引用,value 是强引用。线程池场景下线程长期存活,如果 ThreadLocal 对象被回收而线程没结束,key 变成 null、value 却还被 Entry 强引用,就泄漏了。规范做法是用完必须 remove(),而且要用 try/finally 保证异常路径也清理。另外 ThreadLocal 传不了父线程的值,InheritableThreadLocal 只在创建线程时拷贝一次,线程池里复用线程同样失效。
线程池上下文传递:三种思路。① 提交任务时手动快照,包装成 Runnable 在执行前 set、执行后 remove;② 用阿里开源的 TransmittableThreadLocal(TTL)配合 TtlExecutors 包装线程池,它会在任务提交时刻做快照、执行时回放;③ 干脆不依赖隐式上下文,把需要的参数显式作为方法参数传进去——这也是最不容易出错的方案。MDC 日志上下文同理。
synchronized 与 ReentrantLock:synchronized 是 JVM 关键字,自动加解锁,锁信息记录在对象头 Mark Word 里,偏向锁 → 轻量级锁(CAS 自旋)→ 重量级锁(monitor,涉及用户态到内核态切换)逐级升级且不可逆;ReentrantLock 是 JDK 层的 AQS 实现,需要手动 lock/unlock,但支持公平锁、可中断获取、超时获取和多个 Condition 条件队列。公平锁靠 hasQueuedPredecessors() 判断队列里有没有人在等,非公平锁则先抢一次再排队——非公平吞吐更高,但可能饿死排队线程。
原子类:底层是 CAS + volatile,靠 CPU 的 cmpxchg 指令保证原子性。AtomicInteger 高竞争下会自旋空转,LongAdder 用分段(Cell 数组)把热点分散,sum() 时再汇总,适合高并发计数,但它的 sum() 不是强一致快照。CAS 的经典问题是 ABA,解决办法是加版本号 AtomicStampedReference。
MySQL 隔离级别与幻读:读未提交(脏读)→ 读已提交(不可重复读)→ 可重复读(幻读)→ 串行化。InnoDB 默认 RR,靠 MVCC 的一致性读快照解决不可重复读。幻读在 RR 下用两招压住:快照读靠 ReadView 保证同一事务里看到同一个版本;当前读(SELECT ... FOR UPDATE、UPDATE、DELETE)靠 next-key lock(记录锁 + 间隙锁)锁住区间,阻止其他事务在范围内插入。但间隙锁只在可加锁的索引区间有效,如果查询条件用不上索引,会退化成锁全表。
为什么是 B+ 树:二叉树和红黑树都是二叉结构,树高是 log₂N,几千万行数据树高 20 多层,每层一次磁盘 I/O,扛不住。B 树每个节点既存 key 也存数据,单页能放的 key 少、树更高,且范围查询要在层间回溯。B+ 树只在叶子存数据、非叶子只存 key,单页能塞几百个 key,三层就能覆盖千万级数据;叶子之间还有双向链表,范围查询和排序只需顺着链表扫。所以选型的本质是「把树高压到 3 层以内,把范围扫描变成顺序 I/O」。
ReAct 与 Plan-and-Execute:ReAct 是「思考—行动—观察」逐步循环,每一步都根据最新观察决定下一步,灵活、适合工具结果不确定的探索型任务,但步数不可控、容易绕圈、成本高。Plan-and-Execute 是先把任务拆成计划再按步执行,步骤可控、可审计、可并行,适合流程相对固定的复杂任务,缺点是初始计划一旦失效就要重规划。生产里常组合使用:外层用计划拆解,每个子步骤内部用 ReAct 处理不确定性。
3:15 的夹角:分针指 3(90°),时针在 3 到 4 之间走了 15 分钟,即 15/60 × 30° = 7.5°,所以夹角是 7.5°。