面试现场:水货程序员谢飞机大战Java面试官
第一轮:基础不牢,地动山摇
面试官:谢飞机同学,请介绍一下HashMap的底层实现原理。
谢飞机:HashMap嘛,就是数组加链表!哦对,JDK8以后还有红黑树!
面试官:不错,那什么时候会转换成红黑树呢?
谢飞机:嗯...好像是链表长度超过8的时候?
面试官:很好!那为什么选择8这个阈值呢?
谢飞机:因为...因为8是个好数字?(挠头)
面试官:(无奈)好吧...那说说ArrayList和LinkedList的区别?
谢飞机:ArrayList查询快,LinkedList增删快!
面试官:为什么?
谢飞机:因为...一个用数组,一个用链表!(得意)
面试官:嗯,基础概念还行。
第二轮:并发编程,一脸懵圈
面试官:说说线程池的核心参数有哪些?
谢飞机:核心线程数、最大线程数...还有...还有那个队列大小!
面试官:还有两个参数呢?
谢飞机:啊?还有吗?我以为就这三个...(慌张)
面试官:那说说synchronized和ReentrantLock的区别?
谢飞机:synchronized是关键字,ReentrantLock是类!
面试官:还有什么区别?
谢飞机:ReentrantLock...可以中断?还能设置超时?(不确定的语气)
面试官:Volatile关键字的作用是什么?
谢飞机:保证可见性!禁止指令重排序!(这次回答得很自信)
面试官:不错,这个问题答得挺好。
第三轮:框架源码,彻底露馅
面试官:Spring Bean的生命周期说一下?
谢飞机:实例化、初始化...然后就可以用了!
面试官:具体有哪些步骤?
谢飞机:就是...先new出来,然后调用init方法...(开始胡扯)
面试官:Spring Boot自动配置的原理?
谢飞机:@EnableAutoConfiguration注解!然后...Spring Boot很智能,会自动帮我们配置!(双手一摊)
面试官:Redis缓存穿透怎么解决?
谢飞机:布隆过滤器!还有...缓存空值!
面试官:MySQL索引失效的场景有哪些?
谢飞机:like '%xxx' 会导致失效,还有...函数操作?(声音越来越小)
面试官:好的,谢飞机同学,今天面试就到这里。你先回去等通知吧。
谢飞机:面试官,我能问一下我表现怎么样吗?
面试官:(微笑)你回去等通知就好...
技术答案详解
HashMap底层原理
HashMap在JDK8中的底层实现是数组+链表+红黑树。当链表长度达到8且数组长度>=64时,链表会转换为红黑树,以降低查找时间复杂度从O(n)到O(logn)。选择阈值8是因为泊松分布表明,在随机hashCodes的情况下,链表长度达到8的概率非常低(约0.00000006),所以这是一个合理的平衡点。
ArrayList vs LinkedList
- ArrayList:基于动态数组实现,支持随机访问(O(1)),但在中间插入/删除元素需要移动后续元素(O(n))
- LinkedList:基于双向链表实现,插入/删除操作只需修改指针(O(1)),但随机访问需要遍历(O(n))
线程池核心参数
线程池有7个核心参数:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:非核心线程空闲存活时间
- unit:时间单位
- workQueue:工作队列
- threadFactory:线程工厂
- handler:拒绝策略
synchronized vs ReentrantLock
- synchronized:JVM内置锁,自动释放,不可中断,非公平锁
- ReentrantLock:API层面的锁,需手动释放,可中断,可设置公平/非公平,支持条件变量
Volatile关键字
Volatile提供两个保证:
- 可见性:保证不同线程对变量的操作对其他线程立即可见
- 禁止指令重排序:通过内存屏障防止编译器和处理器重排序
Spring Bean生命周期
完整的Bean生命周期包括:
- 实例化(Instantiation)
- 属性赋值(Populate properties)
- Aware接口回调
- BeanPostProcessor前置处理
- InitializingBean.afterPropertiesSet()和init-method
- BeanPostProcessor后置处理
- 使用阶段
- DisposableBean.destroy()和destroy-method
Spring Boot自动配置原理
通过@EnableAutoConfiguration导入AutoConfigurationImportSelector,该类通过SpringFactoriesLoader加载META-INF/spring.factories中的自动配置类。配合@Conditional系列注解实现条件化配置。
Redis缓存穿透解决方案
- 布隆过滤器:在缓存层前增加布隆过滤器,快速判断key是否存在
- 缓存空值:对查询结果为空的key也进行缓存,设置较短过期时间
- 参数校验:对明显非法的请求参数直接拦截
MySQL索引失效场景
- 最左前缀原则:复合索引未使用最左列
- LIKE模糊查询:'%xxx'开头的模糊查询
- 函数操作:对索引列使用函数或表达式
- 类型转换:字符串和数字比较导致隐式转换
- OR条件:OR连接的条件中部分字段无索引
- NOT条件:使用!=、<>、NOT IN等