XTransfer 后端社招一面:线程池、Full GC 与 Redis 缓存一致性
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 自我介绍。
- 在上家公司有什么收获?
- 平时用过什么 AI 工具?
- 用过哪些设计模式?结合实际场景介绍一下。
- 线程池的核心参数有哪些?核心线程和最大线程有什么区别?
- 为什么不建议使用 JDK 提供的线程池?
- JVM 的垃圾回收机制是怎样的?内存飙高怎么办?
- 什么是 Full GC?为什么会发生 Full GC?老年代不足说明什么?
- 悲观锁和乐观锁分别适用什么场景?
- synchronized 与 ReentrantLock 有什么区别?
- Redis 除了分布式锁还能做哪些缓存场景?如何保证缓存一致?
- 大 key 问题和热 key 问题分别怎么处理?
- MySQL 的慢 SQL 怎么优化?
- 索引在什么时候需要加?
- 手撕:无重复字符的最长子串、最大数。
《参考解析》
线程池与不用 Executors 的原因:参数是 corePoolSize、maximumPoolSize、keepAliveTime、workQueue、threadFactory 和拒绝策略。提交顺序是先占满核心线程、再进队列、队列满才扩到最大线程数、仍满才拒绝。不用 Executors 是因为边界不清:FixedThreadPool 用无界队列会 OOM,CachedThreadPool 的最大线程数是 Integer.MAX_VALUE。
Full GC 与内存飙高:Full GC 多由老年代或元空间不足、晋升失败、显式 System.gc() 触发。老年代不足说明对象活得久或被长生命周期引用拽住,先怀疑无界缓存、只增不删的集合、ThreadLocal 忘记 remove。jstat -gcutil 看回收后能不能降,降不下来就是泄漏,再用 jmap 加 MAT 看引用链。
锁与缓存:悲观锁适合写多冲突高;乐观锁适合读多写少,用版本号和 CAS 重试。synchronized 是 JVM 内置、异常自动释放,ReentrantLock 多了公平锁、可中断和多个 Condition,代价是必须 finally 解锁。缓存一致性走 Cache Aside:更新库后删缓存而非更新缓存,删失败用延迟双删或订阅 binlog;大 key 拆分后 unlink 异步删,热 key 靠本地缓存和限流。
慢 SQL 与手撕:explain 看 type、key、rows、Extra,常见病因是索引列上做函数运算、隐式类型转换、深分页。索引加在高频且区分度高的列上。无重复最长子串用滑动窗口加哈希记上次位置;最大数按 a+b 与 b+a 排序。