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

一、JVM与内存管理

1. 垃圾回收机制对比
2021年面试中,JVM垃圾回收器的选择与调优成为必考题。典型问题如:”CMS与G1回收器的核心差异是什么?在什么场景下选择哪种回收器?”

  • CMS(Concurrent Mark Sweep):基于标记-清除算法,强调低停顿时间,适用于响应时间敏感的Web应用。但存在内存碎片问题,需通过-XX:+UseCMSCompactAtFullCollection参数在Full GC时触发内存整理。
  • G1(Garbage-First):面向大内存(>4GB)场景,通过Region分区实现可预测的停顿时间。其混合回收(Mixed GC)机制同时处理年轻代与老年代对象,适合高吞吐量需求。
    建议:根据业务特性选择回收器,例如电商系统优先G1,而实时交易系统可考虑ZGC(JDK11+)。

2. 类加载机制深度解析
问题示例:”双亲委派模型的作用是什么?如何破坏双亲委派?”

  • 双亲委派模型:类加载器自底向上检查是否已加载类,避免重复加载与安全冲突(如防止java.lang.String被自定义类覆盖)。
  • 破坏双亲委派:通过重写ClassLoader.loadClass()方法或使用线程上下文类加载器(如JDBC驱动加载)。Spring的ClassPathXmlApplicationContext即通过此机制加载用户自定义Bean。
    代码示例
    1. public class CustomClassLoader extends ClassLoader {
    2. @Override
    3. protected Class<?> findClass(String name) throws ClassNotFoundException {
    4. byte[] bytes = loadBytesFromFile(name); // 自定义类加载逻辑
    5. return defineClass(name, bytes, 0, bytes.length);
    6. }
    7. }

二、并发编程与多线程

1. 线程池配置与优化
高频考点:”如何合理配置线程池参数?ThreadPoolExecutor的拒绝策略有哪些?”

  • 核心参数
    • corePoolSize:核心线程数,建议设为NCPU * UCPU * (1 + W/C)(NCPU为CPU核心数,UCPU为目标CPU利用率,W为等待时间,C为计算时间)。
    • maximumPoolSize:最大线程数,需结合任务类型(IO密集型可设为2*NCPU)。
    • keepAliveTime:非核心线程空闲存活时间。
  • 拒绝策略
    • AbortPolicy(默认):抛出RejectedExecutionException
    • CallerRunsPolicy:由提交任务的线程直接执行。
      实践建议:使用Executors.newFixedThreadPool()时需注意无界队列可能导致OOM,推荐显式创建ThreadPoolExecutor

2. 并发工具类实战
问题示例:”CountDownLatchCyclicBarrier的区别是什么?”

  • CountDownLatch:单向等待,适用于主线程等待多个子任务完成(如并行测试)。
    1. CountDownLatch latch = new CountDownLatch(3);
    2. for (int i = 0; i < 3; i++) {
    3. new Thread(() -> {
    4. System.out.println("Task completed");
    5. latch.countDown();
    6. }).start();
    7. }
    8. latch.await(); // 主线程阻塞
  • CyclicBarrier:循环等待,适用于多线程分阶段协作(如游戏回合制)。
    1. CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("All ready"));
    2. new Thread(() -> {
    3. try {
    4. barrier.await(); // 等待其他线程
    5. } catch (Exception e) {}
    6. }).start();

三、Spring框架核心

1. IoC与AOP实现原理
典型问题:”Spring如何解决循环依赖?AOP的动态代理方式有哪些?”

  • 循环依赖处理:Spring通过三级缓存(singletonFactoriesearlySingletonObjectssingletonObjects)解决构造器循环依赖,但仅支持单例作用域的setter注入。
  • AOP代理
    • JDK动态代理:基于接口,通过Proxy.newProxyInstance()生成代理类。
    • CGLIB代理:基于继承,适用于无接口类,需注意final方法无法代理。
      代码示例
      1. // JDK动态代理
      2. public class LoggingProxy implements InvocationHandler {
      3. private Object target;
      4. public Object invoke(Object proxy, Method method, Object[] args) {
      5. System.out.println("Before method: " + method.getName());
      6. return method.invoke(target, args);
      7. }
      8. }

2. 事务传播行为
高频考点:”PROPAGATION_REQUIREDPROPAGATION_REQUIRES_NEW的区别?”

  • REQUIRED:加入当前事务,若不存在则新建(默认行为)。
  • REQUIRES_NEW:总是新建事务,挂起当前事务(适用于日志记录等独立操作)。
    配置示例
    1. @Transactional(propagation = Propagation.REQUIRES_NEW)
    2. public void independentOperation() {
    3. // 独立事务逻辑
    4. }

四、数据库与SQL优化

1. 索引失效场景
问题示例:”哪些情况下MySQL索引会失效?”

  • 隐式类型转换:如where numeric_column = '123'
  • 使用函数where DATE(create_time) = '2021-01-01'
  • OR条件:除非所有列均有索引,否则可能全表扫描。
    优化建议:使用EXPLAIN分析执行计划,重点关注type列(应避免ALL全表扫描)。

2. 事务隔离级别
典型问题:”READ COMMITTEDREPEATABLE READ的区别?MySQL默认级别是什么?”

  • READ COMMITTED:允许不可重复读,但避免脏读(Oracle默认)。
  • REPEATABLE READ:避免不可重复读,但可能幻读(MySQL默认,通过MVCC与Next-Key锁解决)。
    设置方式
    1. SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

五、分布式与微服务

1. 分布式锁实现
高频考点:”如何用Redis实现分布式锁?需要注意哪些问题?”

  • Redisson方案
    1. RLock lock = redissonClient.getLock("order_lock");
    2. lock.lock(); // 默认30秒超时
    3. try {
    4. // 业务逻辑
    5. } finally {
    6. lock.unlock();
    7. }
  • 注意事项
    • 需设置超时时间防止死锁。
    • 使用SETNX + EXPIRE原子命令(Redis 2.6.12+支持SET key value NX EX 30)。

2. 微服务注册中心对比
问题示例:”Eureka与Nacos的核心差异是什么?”

  • Eureka:AP架构(高可用优先),适用于Spring Cloud生态。
  • Nacos:支持CP/AP模式切换,集成配置中心功能,适合多语言环境。
    选型建议:中小型项目可选Eureka,大型分布式系统推荐Nacos。

六、备考策略与建议

  1. 源码阅读:重点掌握HashMapConcurrentHashMapAQS等核心类源码。
  2. 项目复盘:将实际项目中的技术难点(如分布式事务、高并发优化)与面试题结合。
  3. 模拟面试:通过LeetCode(算法)、牛客网(Java专题)进行针对性练习。

结语:2021年Java面试更注重底层原理与工程实践能力,建议开发者在掌握基础的同时,深入理解技术选型的背景与权衡。通过系统性复习与实战演练,可显著提升面试成功率。