2021 Java面试真题深度解析:技术要点与实战策略

一、JVM基础与内存管理

真题1:JVM内存模型由哪些区域组成?各区域的作用是什么?
JVM内存模型分为方法区、堆、虚拟机栈、本地方法栈和程序计数器。堆是线程共享区域,存储对象实例和数组,是垃圾回收(GC)的主要区域;方法区存储类信息、常量、静态变量等,JDK8后由元空间(Metaspace)替代永久代;虚拟机栈为线程私有,每个方法执行时创建栈帧,存储局部变量表、操作数栈等。例如,int a = 10;的局部变量a存储在栈帧的局部变量表中。

真题2:如何判断对象是否存活?引用计数法与可达性分析法的区别是什么?
引用计数法通过统计对象被引用的次数判断存活,但无法处理循环引用问题;可达性分析法以GC Roots(如虚拟机栈中的对象引用、方法区中的静态变量)为起点,通过引用链判断对象是否可达。Java采用后者,例如:

  1. Object obj1 = new Object(); // obj1为GC Roots可达对象
  2. Object obj2 = new Object();
  3. obj1.ref = obj2; obj2.ref = obj1; // 循环引用,但若obj1无其他引用,仍会被回收

真题3:常见的垃圾回收算法有哪些?各适用于什么场景?

  • 标记-清除:标记无用对象后直接清除,产生内存碎片,适用于老年代。
  • 复制算法:将内存分为两块,存活对象复制到另一块后清理原区域,无碎片但空间利用率低,适用于新生代(Eden:Survivor=8:1:1)。
  • 标记-整理:标记后整理存活对象到一端,清理边界外内存,适用于老年代。
  • 分代收集:结合上述算法,新生代用复制算法,老年代用标记-清除或标记-整理。

二、Java并发编程与多线程

真题4:synchronized与ReentrantLock的区别是什么?

  • 锁的实现:synchronized是JVM内置关键字,ReentrantLock是API实现的锁。
  • 公平性:synchronized为非公平锁,ReentrantLock可配置公平/非公平模式。
  • 功能扩展:ReentrantLock支持条件变量(Condition)、可中断锁、超时获取锁等。例如:
    1. Lock lock = new ReentrantLock();
    2. Condition condition = lock.newCondition();
    3. lock.lock();
    4. try {
    5. while (conditionNotMet) {
    6. condition.await(); // 释放锁并等待
    7. }
    8. } finally {
    9. lock.unlock();
    10. }

真题5:volatile关键字的作用是什么?如何保证可见性和有序性?
volatile修饰的变量保证每次读写都直接操作主内存,避免线程工作内存中的缓存不一致(可见性)。通过插入内存屏障(Memory Barrier)禁止指令重排序(有序性)。例如,双重检查锁定(DCL)单例模式中需用volatile防止指令重排序导致对象未初始化:

  1. public class Singleton {
  2. private static volatile Singleton instance;
  3. private Singleton() {}
  4. public static Singleton getInstance() {
  5. if (instance == null) {
  6. synchronized (Singleton.class) {
  7. if (instance == null) {
  8. instance = new Singleton(); // 防止指令重排序
  9. }
  10. }
  11. }
  12. return instance;
  13. }
  14. }

真题6:线程池的核心参数有哪些?如何配置合理参数?
线程池参数包括核心线程数(corePoolSize)、最大线程数(maximumPoolSize)、空闲线程存活时间(keepAliveTime)、任务队列(workQueue)和拒绝策略(RejectedExecutionHandler)。配置建议:

  • CPU密集型任务:核心线程数≈CPU核心数(避免过多线程竞争CPU)。
  • IO密集型任务:核心线程数可适当增大(如CPU核心数*2),利用线程等待IO的时间处理其他任务。
  • 队列选择:无界队列(如LinkedBlockingQueue)可能导致OOM,建议使用有界队列(如ArrayBlockingQueue)配合拒绝策略(如CallerRunsPolicy)。

三、Spring框架与源码解析

真题7:Spring Bean的生命周期是怎样的?

  1. 实例化:通过反射或工厂方法创建Bean实例。
  2. 属性赋值:依赖注入(DI)设置Bean的属性。
  3. 初始化前:调用BeanPostProcessorpostProcessBeforeInitialization方法。
  4. 初始化:执行InitializingBeanafterPropertiesSet或自定义init-method
  5. 初始化后:调用BeanPostProcessorpostProcessAfterInitialization方法(如AOP代理在此生成)。
  6. 销毁:容器关闭时调用DisposableBeandestroy或自定义destroy-method

真题8:Spring AOP的实现原理是什么?
Spring AOP基于动态代理,JDK动态代理(接口代理)和CGLIB(子类代理)。当Bean实现接口时使用JDK代理,否则使用CGLIB。例如:

  1. @Aspect
  2. @Component
  3. public class LoggingAspect {
  4. @Before("execution(* com.example.service.*.*(..))")
  5. public void logBefore(JoinPoint joinPoint) {
  6. System.out.println("Method called: " + joinPoint.getSignature().getName());
  7. }
  8. }

代理对象在方法调用前后织入切面逻辑。

真题9:Spring事务的传播行为有哪些?

  • REQUIRED:默认行为,加入当前事务,若无则新建。
  • SUPPORTS:支持当前事务,若无则以非事务方式执行。
  • MANDATORY:必须存在事务,否则抛出异常。
  • REQUIRES_NEW:新建事务,挂起当前事务(如日志记录需独立提交)。
  • NOT_SUPPORTED:以非事务方式执行,挂起当前事务。
  • NEVER:以非事务方式执行,若存在事务则抛出异常。
  • NESTED:嵌套事务,子事务回滚不影响父事务(需数据库支持保存点)。

四、数据库与SQL优化

真题10:MySQL的索引类型有哪些?如何优化索引使用?

  • 普通索引:最基本的索引类型。
  • 唯一索引:列值必须唯一,允许NULL值。
  • 主键索引:特殊的唯一索引,不允许NULL值。
  • 联合索引:多列组合索引,遵循最左前缀原则。例如,索引(a,b,c)可优化a=1a=1 AND b=2,但无法优化b=2
  • 覆盖索引:查询列全部在索引中,避免回表。例如:
    1. CREATE INDEX idx_name_age ON user(name, age);
    2. SELECT name, age FROM user WHERE name = 'Alice'; -- 使用覆盖索引

真题11:事务的隔离级别有哪些?各解决什么问题?

  • 读未提交(Read Uncommitted):可能读到未提交的数据(脏读)。
  • 读已提交(Read Committed):解决脏读,但可能不可重复读。
  • 可重复读(Repeatable Read):解决不可重复读,但可能幻读(MySQL通过MVCC和间隙锁解决)。
  • 串行化(Serializable):最高隔离级别,通过加锁避免并发问题,但性能最低。

五、总结与建议

2021年Java面试题聚焦底层原理(如JVM、并发)、框架源码(如Spring)和工程实践(如线程池配置、SQL优化)。建议开发者:

  1. 深入原理:理解GC算法、锁升级过程等底层机制。
  2. 结合源码:阅读Spring、Netty等框架的核心代码。
  3. 实战演练:通过LeetCode、设计模式项目提升编码能力。
  4. 关注更新:学习Java 15+的新特性(如密封类、记录类)。

掌握这些要点,不仅能应对面试,更能提升实际开发中的问题解决能力。