一、JVM与内存管理:从原理到实践
1. JVM内存模型与垃圾回收机制
2021年面试中,JVM相关问题占比超30%,重点考察内存分区与GC算法。例如:
- 问题:JVM堆内存如何划分?各区域作用是什么?
解析:堆内存分为新生代(Eden、Survivor)、老年代。Eden区存放新对象,Survivor区通过复制算法(From→To)减少内存碎片,老年代存储长期存活对象。Full GC触发条件包括老年代空间不足或System.gc()调用。
代码示例:// 模拟对象晋升至老年代public class GCDemo {public static void main(String[] args) {byte[] hugeArray = new byte[10 * 1024 * 1024]; // 分配10MB对象System.out.println("对象分配在Eden区");// 多次GC后,对象可能晋升至老年代}}
建议:掌握
-Xms、-Xmx等JVM参数调优,结合VisualVM或JProfiler分析GC日志。
2. 类加载机制与双亲委派模型
- 问题:双亲委派模型的作用及破坏场景?
解析:双亲委派通过从下至上检查类是否已加载,避免类冲突(如避免用户自定义java.lang.String覆盖JDK类)。破坏场景包括线程上下文类加载器(如JDBC驱动加载)。
代码示例:// 自定义类加载器(需继承ClassLoader)public class CustomClassLoader extends ClassLoader {@Overrideprotected Class<?> findClass(String name) {// 自定义类加载逻辑return super.findClass(name);}}
二、多线程与并发编程:核心机制与陷阱
1. synchronized与Lock对比
- 问题:ReentrantLock相比synchronized的优势?
解析:ReentrantLock支持公平锁、可中断锁、超时获取锁等特性,适用于高并发场景。
代码示例:Lock lock = new ReentrantLock();lock.lock(); // 获取锁try {// 临界区代码} finally {lock.unlock(); // 必须释放锁}
建议:优先使用
synchronized简化代码,复杂场景(如读写分离)选择ReentrantReadWriteLock。
2. 线程池参数配置
- 问题:如何合理设置线程池核心参数?
解析:核心参数包括corePoolSize(核心线程数)、maximumPoolSize(最大线程数)、keepAliveTime(空闲线程存活时间)。任务队列选择需考虑吞吐量(ArrayBlockingQueue)与拒绝策略(如AbortPolicy抛出异常)。
代码示例:ExecutorService executor = new ThreadPoolExecutor(5, // corePoolSize10, // maximumPoolSize60, TimeUnit.SECONDS, // keepAliveTimenew LinkedBlockingQueue<>(100), // 任务队列new ThreadPoolExecutor.AbortPolicy() // 拒绝策略);
三、Spring框架:核心机制与源码解析
1. Spring IoC与DI实现原理
- 问题:Spring如何通过反射实现依赖注入?
解析:Spring通过BeanFactory或ApplicationContext加载Bean定义,利用反射调用构造方法或setter方法注入依赖。
代码示例:// 用户类public class UserService {private UserRepository repository;public void setRepository(UserRepository repository) {this.repository = repository;}}// XML配置<bean id="userService" class="com.example.UserService"><property name="repository" ref="userRepository"/></bean>
2. AOP实现方式与适用场景
- 问题:JDK动态代理与CGLIB代理的区别?
解析:JDK动态代理基于接口,通过InvocationHandler实现;CGLIB通过继承目标类生成子类,适用于无接口场景。Spring默认对接口使用JDK代理,对类使用CGLIB。
代码示例:// JDK动态代理示例public interface LogService {void log(String message);}public class LogServiceImpl implements LogService {public void log(String message) {System.out.println("Log: " + message);}}// 代理类public class LogProxy implements InvocationHandler {private Object target;public LogProxy(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) {System.out.println("Before method");return method.invoke(target, args);}}// 创建代理对象LogService proxy = (LogService) Proxy.newProxyInstance(LogService.class.getClassLoader(),new Class[]{LogService.class},new LogProxy(new LogServiceImpl()));
四、数据库与SQL优化:从索引到事务
1. MySQL索引失效场景
- 问题:哪些情况会导致索引失效?
解析:常见场景包括对列使用函数(如WHERE DATE(create_time) = '2021-01-01')、隐式类型转换(如字符串与数字比较)、OR条件未全部使用索引列。
优化建议:使用EXPLAIN分析执行计划,避免全表扫描。
2. 事务隔离级别与实现
- 问题:MySQL默认隔离级别及可能的问题?
解析:MySQL默认REPEATABLE READ,通过MVCC(多版本并发控制)实现,可能产生幻读(需通过SELECT ... FOR UPDATE加锁解决)。
代码示例:-- 设置事务隔离级别SET TRANSACTION ISOLATION LEVEL READ COMMITTED;-- 开启事务START TRANSACTION;SELECT * FROM accounts WHERE user_id = 1 FOR UPDATE; -- 加锁UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;COMMIT;
五、综合问题:系统设计与算法
1. 高并发系统设计要点
- 问题:如何设计一个秒杀系统?
解析:核心策略包括限流(如令牌桶算法)、异步处理(消息队列)、库存预热(Redis预减库存)、防超卖(乐观锁或分布式锁)。
架构示例:用户请求 → Nginx负载均衡 → 网关限流 → 消息队列(Kafka) → 服务层处理 → 数据库(分库分表)
2. 算法题:链表反转
- 问题:如何反转单链表?
解析:迭代法时间复杂度O(n),空间复杂度O(1)。
代码示例:public ListNode reverseList(ListNode head) {ListNode prev = null;ListNode curr = head;while (curr != null) {ListNode next = curr.next;curr.next = prev;prev = curr;curr = next;}return prev;}
六、面试准备建议
- 系统复习:按JVM、多线程、Spring、数据库等模块分类整理知识点。
- 代码实践:通过LeetCode或自定义项目练习算法与系统设计。
- 模拟面试:与同行进行Mock Interview,重点训练表达逻辑。
- 关注动态:跟踪Java 11+新特性(如Var关键字、模块化系统)。
结语:2021年Java面试题更注重底层原理与实战能力,掌握本文所述核心知识点,结合持续练习,可显著提升面试通过率。