面试官:谢飞机,Java 面试3轮20问,你答对几个?

第一轮:基础不牢,地动山摇

面试官:谢飞机,先做个自我介绍吧。

谢飞机:我叫谢飞机,喜欢打飞机……啊不对,写代码!

面试官(皱眉):……好吧。那说说 HashMap 的底层结构?

谢飞机:HashMap 是数组加链表,JDK8 以后链表长了会变红黑树!

面试官(点头):不错。那为什么用红黑树不用 AVL 树?

谢飞机:因为……红黑树比较红?

面试官:……行吧。ArrayList 和 LinkedList 有什么区别?

谢飞机:一个用数组,一个用链表,查得快还是插得快,我记混了。

面试官:那你平时用哪个?

谢飞机:我都用 ArrayList,因为名字短。


第二轮:并发与框架,有点懵

面试官:说说线程池的核心参数?

谢飞机:corePoolSize、maximumPoolSize、workQueue、还有……threadFactory?

面试官:不错。那拒绝策略有哪些?

谢飞机:有 CallerRunsPolicy、AbortPolicy……还有两个,我忘了,反正都挺暴躁的。

面试官:Spring Bean 的生命周期了解吗?

谢飞机:new 一下,然后@Autowired,就活了。

面试官:……MyBatis #{} 和 ${} 有什么区别?

谢飞机:一个带引号,一个不带?反正 ${} 容易被 SQL 注入,老板不让用。


第三轮:分布式与中间件,彻底飞了

面试官:Redis 缓存穿透怎么解决?

谢飞机:加布隆过滤器!或者……缓存空值?

面试官(略惊讶):嗯,还行。那缓存雪崩呢?

谢飞机:给 key 加个随机过期时间,别一起死。

面试官:MySQL 索引失效的场景有哪些?

谢飞机:like 开头是%,还有函数操作字段……其他的,我靠索引优化器自动选。

面试官:Dubbo 的负载均衡策略?

谢飞机:有随机、轮询、最少活跃……还有一个一致性哈希,我用来分库分表。

面试官:xxl-job 怎么保证任务不重复执行?

谢飞机:它……有个锁?数据库行锁?

面试官(叹气):好的谢飞机,今天先到这里,你回去等通知吧。

谢飞机:是不是没戏了?

面试官:……你猜。


附:技术问题详解

1. HashMap 底层结构及红黑树选择原因

  • 结构:JDK 1.8 后,HashMap 由 数组 + 链表/红黑树 构成。当链表长度 ≥ 8 且数组长度 ≥ 64 时,链表转为红黑树,以提升查询效率(O(n) → O(log n))。
  • 为何选红黑树而非 AVL:红黑树的 插入/删除性能更优(最多 2 次旋转),AVL 树追求严格平衡(旋转次数多),适合读多写少场景;HashMap 更注重综合性能。

2. ArrayList vs LinkedList

  • ArrayList:基于动态数组,随机访问快(O(1)),增删慢(需移动元素,O(n))。
  • LinkedList:基于双向链表,增删快(O(1)),随机访问慢(需遍历,O(n))。
  • 使用建议:高频查询用 ArrayList,高频增删用 LinkedList(但实际因缓存局部性,ArrayList 综合性能常更优)。

3. 线程池核心参数与拒绝策略

  • 核心参数:
    • corePoolSize:核心线程数(即使空闲也不销毁)。
    • maximumPoolSize:最大线程数。
    • workQueue:阻塞队列(如 ArrayBlockingQueue、LinkedBlockingQueue)。
    • keepAliveTime:非核心线程空闲存活时间。
    • threadFactory:线程创建工厂。
    • handler:拒绝策略。
  • 拒绝策略:
    • AbortPolicy:直接抛出 RejectedExecutionException(默认)。
    • CallerRunsPolicy:由调用线程执行任务。
    • DiscardPolicy:静默丢弃任务。
    • DiscardOldestPolicy:丢弃队列最旧任务,尝试重新提交。

4. Spring Bean 生命周期

  1. 实例化(Instantiation)
  2. 属性赋值(Populate Properties)
  3. Aware 接口回调(如 BeanNameAware)
  4. BeanPostProcessor.postProcessBeforeInitialization
  5. InitializingBean.afterPropertiesSet / @PostConstruct
  6. BeanPostProcessor.postProcessAfterInitialization
  7. 使用阶段
  8. DisposableBean.destroy / @PreDestroy

5. MyBatis #{} 与 ${}

  • #{}:预编译处理(PreparedStatement),自动加引号,防 SQL 注入。
  • ${}:字符串替换(Statement),直接拼接,有注入风险,仅用于动态表名/列名等场景。

6. Redis 缓存问题解决方案

  • 缓存穿透:查询不存在的数据,绕过缓存直击 DB。
    • 方案:布隆过滤器拦截无效请求;缓存空值(设置短 TTL)。
  • 缓存雪崩:大量 key 同时过期,导致 DB 瞬时压力激增。
    • 方案:设置随机过期时间;热点数据永不过期;集群部署+熔断降级。

7. MySQL 索引失效场景

  • 对字段使用函数或运算(如 WHERE YEAR(create_time) = 2023)。
  • 隐式类型转换(如字符串字段用数字查询)。
  • LIKE 以通配符开头(LIKE '%abc')。
  • OR 条件中部分字段无索引。
  • 复合索引未遵循最左前缀原则。

8. Dubbo 负载均衡策略

  • RandomLoadBalance:随机(默认,加权)。
  • RoundRobinLoadBalance:轮询(加权,平滑)。
  • LeastActiveLoadBalance:最少活跃调用(响应慢的节点分配更少请求)。
  • ConsistentHashLoadBalance:一致性哈希(相同参数请求总到同一节点,用于缓存场景)。

9. xxl-job 任务去重机制

  • 基于数据库行锁:调度中心触发任务时,通过 SELECT ... FOR UPDATE 锁定任务记录,确保同一任务同一时间仅被一个执行器获取。
  • 执行器集群:任务路由策略(如 SHARDING_BROADCAST)可控制分片逻辑,避免重复执行。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐