2021 Java面试真题全解析:技术深度与实战攻略

一、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: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

代码示例

  1. // ReentrantLock可中断锁示例
  2. Lock lock = new ReentrantLock();
  3. try {
  4. lock.lockInterruptibly(); // 支持中断
  5. // 临界区代码
  6. } catch (InterruptedException e) {
  7. Thread.currentThread().interrupt(); // 恢复中断状态
  8. } finally {
  9. lock.unlock();
  10. }

真题4:线程池参数配置与拒绝策略
企业常通过线程池考察候选人对资源管理的理解,需掌握:

  • 核心参数
    • corePoolSize:核心线程数(常驻线程)。
    • maximumPoolSize:最大线程数(任务队列满时创建)。
    • keepAliveTime:空闲线程存活时间。
    • workQueue:任务队列(ArrayBlockingQueueLinkedBlockingQueueSynchronousQueue)。
  • 拒绝策略
    • AbortPolicy(默认):抛出RejectedExecutionException
    • CallerRunsPolicy:由调用线程执行任务。
    • DiscardPolicy:静默丢弃。
    • DiscardOldestPolicy:丢弃队列最旧任务。

建议:根据任务类型(CPU密集型corePoolSize=N+1,IO密集型corePoolSize=2*N)和QPS压力配置参数,避免SynchronousQueue直接触发拒绝策略。

三、Spring框架与源码解析

真题5:Spring Bean生命周期详解
Spring作为Java生态核心,生命周期题是区分初级与高级开发者的关键:

  1. 实例化:通过构造方法或工厂创建Bean实例。
  2. 属性注入:依赖注入(@Autowired、XML配置)。
  3. 初始化前:调用BeanPostProcessor.postProcessBeforeInitialization()(如@PostConstruct)。
  4. 初始化:执行InitializingBean.afterPropertiesSet()@Bean(initMethod)
  5. 初始化后:调用BeanPostProcessor.postProcessAfterInitialization()(如AOP代理)。
  6. 销毁:执行DisposableBean.destroy()@Bean(destroyMethod)

真题6:AOP实现原理与动态代理
AOP题考察对Spring核心机制的理解,需掌握:

  • JDK动态代理:基于接口,通过Proxy.newProxyInstance()生成代理类。
  • CGLIB代理:基于子类,通过MethodInterceptor拦截方法调用(需注意final方法无法代理)。
  • Spring选择策略:默认对接口使用JDK代理,对类使用CGLIB(可通过@EnableAspectJAutoProxy(proxyTargetClass=true)强制使用CGLIB)。

代码示例

  1. // JDK动态代理示例
  2. public interface UserService {
  3. void addUser();
  4. }
  5. public class UserServiceImpl implements UserService {
  6. @Override
  7. public void addUser() {
  8. System.out.println("Add user");
  9. }
  10. }
  11. public class ProxyFactory implements InvocationHandler {
  12. private Object target;
  13. public ProxyFactory(Object target) {
  14. this.target = target;
  15. }
  16. @Override
  17. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  18. System.out.println("Before method");
  19. Object result = method.invoke(target, args);
  20. System.out.println("After method");
  21. return result;
  22. }
  23. public static void main(String[] args) {
  24. UserService userService = new UserServiceImpl();
  25. UserService proxy = (UserService) Proxy.newProxyInstance(
  26. userService.getClass().getClassLoader(),
  27. userService.getClass().getInterfaces(),
  28. new ProxyFactory(userService));
  29. proxy.addUser();
  30. }
  31. }

四、数据库与分布式系统

真题7:MySQL索引优化与执行计划分析
数据库题考察候选人对性能优化的实战能力,需掌握:

  • 索引类型:B+树索引(适合范围查询)、哈希索引(仅等值查询)。
  • 索引失效场景
    • 列参与计算(WHERE YEAR(create_time) = 2021)。
    • 使用NOT!=OR(需确保OR条件均索引)。
    • 隐式类型转换(如字符串列用数字查询)。
  • 执行计划分析:通过EXPLAIN查看typeconst > eq_ref > range > index > ALL)、key(是否使用索引)、extraUsing filesortUsing temporary需优化)。

真题8:分布式锁实现与Redis应用
分布式系统题是2021年面试热点,需掌握:

  • Redis实现分布式锁
    • SETNX + 过期时间(避免死锁)。
    • Redlock算法(多Redis节点投票,但存在争议)。
    • Redisson框架(看门狗机制自动续期)。
  • Zookeeper实现:基于临时顺序节点,通过监听前驱节点释放实现锁。

建议:高并发场景优先选择Redisson,需注意锁超时(leaseTime)与业务执行时间的匹配。

五、总结与备考建议

2021年Java面试真题呈现以下趋势:

  1. 深度优先:从“是什么”转向“为什么”,如JVM调优需结合具体业务场景。
  2. 实战导向:代码题占比提升,需掌握手写单例、线程池等高频题型。
  3. 框架源码:Spring、MyBatis等框架需理解核心机制(如IoC、AOP)。

备考建议

  • 理论+实践:通过LeetCode刷题提升编码能力,结合实际项目优化GC、线程池等参数。
  • 源码阅读:重点分析Spring、Netty等框架的核心类(如DefaultListableBeanFactoryNioEventLoop)。
  • 模拟面试:通过社区(如牛客网)参与模拟面试,积累答题经验。

本文汇总的2021年Java面试真题覆盖了JVM、并发、Spring、数据库等核心领域,结合企业用人需求与开发者痛点,提供了深度解析与实战建议,助力读者高效备考。