一、JVM基础与内存管理
真题1:Java内存区域如何划分?各区域作用及常见OOM场景
JVM内存模型是面试必考点,2021年真题中频繁出现对堆、栈、方法区等区域的细节考察。
- 堆(Heap):存储对象实例,分为新生代(Eden、Survivor)和老年代。OOM常见于内存泄漏(如静态集合未释放)或分配不足(
-Xmx参数设置过小)。 - 栈(Stack):存储方法调用栈帧,包含局部变量表、操作数栈等。栈溢出(
StackOverflowError)通常由递归过深或线程栈设置过小(-Xss)导致。 - 方法区(Metaspace):存储类元数据、常量池等。JDK8后移至元空间(本地内存),OOM多因动态生成类过多(如CGLIB代理)。
真题2:垃圾回收算法与常见收集器对比
企业关注候选人对GC调优的实战能力,需掌握以下要点:
- 标记-清除:产生碎片,需配合压缩(如Serial Old)。
- 复制算法:新生代Survivor区设计(Eden:Survivor=8
1),减少复制开销。 - 分代收集:根据对象存活周期选择算法(新生代用复制,老年代用标记-整理)。
- 收集器对比:
- Parallel Scavenge/Old:吞吐量优先,适合后台计算。
- CMS:低停顿,但可能产生浮动垃圾。
- G1:区域化分代,平衡吞吐与停顿,需关注
-XX:MaxGCPauseMillis参数。
建议:通过jstat -gcutil <pid>监控GC日志,结合业务场景调整参数(如CMS触发阈值-XX:CMSInitiatingOccupancyFraction)。
二、并发编程与多线程
真题3:synchronized与ReentrantLock的区别
2021年面试中,锁的对比题占比超30%,需从多个维度分析:
- 实现机制:
synchronized依赖JVM内置锁,ReentrantLock基于AQS(AbstractQueuedSynchronizer)。 - 公平性:
ReentrantLock可配置公平锁(减少线程饥饿),synchronized非公平。 - 功能扩展:
ReentrantLock支持可中断锁(lockInterruptibly())、超时获取(tryLock(timeout)),适合复杂场景。 - 性能:JDK6后
synchronized优化(锁消除、偏向锁),低竞争下性能接近ReentrantLock。
代码示例:
// ReentrantLock可中断锁示例Lock lock = new ReentrantLock();try {lock.lockInterruptibly(); // 支持中断// 临界区代码} catch (InterruptedException e) {Thread.currentThread().interrupt(); // 恢复中断状态} finally {lock.unlock();}
真题4:线程池参数配置与拒绝策略
企业常通过线程池考察候选人对资源管理的理解,需掌握:
- 核心参数:
corePoolSize:核心线程数(常驻线程)。maximumPoolSize:最大线程数(任务队列满时创建)。keepAliveTime:空闲线程存活时间。workQueue:任务队列(ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue)。
- 拒绝策略:
AbortPolicy(默认):抛出RejectedExecutionException。CallerRunsPolicy:由调用线程执行任务。DiscardPolicy:静默丢弃。DiscardOldestPolicy:丢弃队列最旧任务。
建议:根据任务类型(CPU密集型corePoolSize=N+1,IO密集型corePoolSize=2*N)和QPS压力配置参数,避免SynchronousQueue直接触发拒绝策略。
三、Spring框架与源码解析
真题5:Spring Bean生命周期详解
Spring作为Java生态核心,生命周期题是区分初级与高级开发者的关键:
- 实例化:通过构造方法或工厂创建Bean实例。
- 属性注入:依赖注入(
@Autowired、XML配置)。 - 初始化前:调用
BeanPostProcessor.postProcessBeforeInitialization()(如@PostConstruct)。 - 初始化:执行
InitializingBean.afterPropertiesSet()或@Bean(initMethod)。 - 初始化后:调用
BeanPostProcessor.postProcessAfterInitialization()(如AOP代理)。 - 销毁:执行
DisposableBean.destroy()或@Bean(destroyMethod)。
真题6:AOP实现原理与动态代理
AOP题考察对Spring核心机制的理解,需掌握:
- JDK动态代理:基于接口,通过
Proxy.newProxyInstance()生成代理类。 - CGLIB代理:基于子类,通过
MethodInterceptor拦截方法调用(需注意final方法无法代理)。 - Spring选择策略:默认对接口使用JDK代理,对类使用CGLIB(可通过
@EnableAspectJAutoProxy(proxyTargetClass=true)强制使用CGLIB)。
代码示例:
// JDK动态代理示例public interface UserService {void addUser();}public class UserServiceImpl implements UserService {@Overridepublic void addUser() {System.out.println("Add user");}}public class ProxyFactory implements InvocationHandler {private Object target;public ProxyFactory(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method");Object result = method.invoke(target, args);System.out.println("After method");return result;}public static void main(String[] args) {UserService userService = new UserServiceImpl();UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),new ProxyFactory(userService));proxy.addUser();}}
四、数据库与分布式系统
真题7:MySQL索引优化与执行计划分析
数据库题考察候选人对性能优化的实战能力,需掌握:
- 索引类型:B+树索引(适合范围查询)、哈希索引(仅等值查询)。
- 索引失效场景:
- 列参与计算(
WHERE YEAR(create_time) = 2021)。 - 使用
NOT、!=、OR(需确保OR条件均索引)。 - 隐式类型转换(如字符串列用数字查询)。
- 列参与计算(
- 执行计划分析:通过
EXPLAIN查看type(const>eq_ref>range>index>ALL)、key(是否使用索引)、extra(Using filesort、Using temporary需优化)。
真题8:分布式锁实现与Redis应用
分布式系统题是2021年面试热点,需掌握:
- Redis实现分布式锁:
SETNX+ 过期时间(避免死锁)。- Redlock算法(多Redis节点投票,但存在争议)。
- Redisson框架(看门狗机制自动续期)。
- Zookeeper实现:基于临时顺序节点,通过监听前驱节点释放实现锁。
建议:高并发场景优先选择Redisson,需注意锁超时(leaseTime)与业务执行时间的匹配。
五、总结与备考建议
2021年Java面试真题呈现以下趋势:
- 深度优先:从“是什么”转向“为什么”,如JVM调优需结合具体业务场景。
- 实战导向:代码题占比提升,需掌握手写单例、线程池等高频题型。
- 框架源码:Spring、MyBatis等框架需理解核心机制(如IoC、AOP)。
备考建议:
- 理论+实践:通过LeetCode刷题提升编码能力,结合实际项目优化GC、线程池等参数。
- 源码阅读:重点分析Spring、Netty等框架的核心类(如
DefaultListableBeanFactory、NioEventLoop)。 - 模拟面试:通过社区(如牛客网)参与模拟面试,积累答题经验。
本文汇总的2021年Java面试真题覆盖了JVM、并发、Spring、数据库等核心领域,结合企业用人需求与开发者痛点,提供了深度解析与实战建议,助力读者高效备考。