华兴致远 Java开发 二面
#JAVA##JAVA面经##JAVA内推#
1. Redis 分布式锁在主从切换时为什么会出现锁丢失?
思路 核心是主从异步复制:主节点加锁成功但未同步到从节点,主宕机后从升主,新主无锁数据,导致多个客户端重复加锁。
回答示例
Redis 主从架构下锁丢失的核心原因是主从数据异步复制:
- 客户端 A 向主节点发起 SET NX 加锁,主节点加锁成功;
- 主节点还没来得及把“锁数据”同步到从节点,主节点宕机;
- 哨兵/集群触发主从切换,从节点升级为新主节点,但新主节点没有客户端 A 的锁数据;
- 客户端 B 向新主节点加锁,成功获取到同一把锁,导致锁丢失、分布式锁互斥性被破坏。
解决方案:用 Redisson 红锁(多实例加锁)、或 Redis Cluster 仲裁机制,避免单主依赖。
2. MyBatis 预编译底层是如何防止 SQL 注入的?
思路 核心是 JDBC PreparedStatement 预编译:参数与 SQL 模板分离,参数被当作“值”而非“SQL 指令”解析。
回答示例
MyBatis 预编译防注入的核心依赖 JDBC 的 PreparedStatement,底层逻辑:
- #{} 会把 SQL 模板(如
select * from user where id = ?)发送给数据库,数据库先编译这个模板,生成执行计划; - 把参数值(如
1 or 1=1)传入编译后的模板,数据库只会把参数当作“纯字符串值”处理,不会解析成 SQL 指令; - 而 ${} 是直接拼接字符串,参数中的
or 1=1会被当作 SQL 指令执行,因此会产生注入。
简单说:预编译让“SQL 结构”和“参数值”彻底分离,参数无法改变 SQL 执行逻辑,从而杜绝注入。
3. InnoDB 可重复读是如何通过 MVCC 实现一致性视图的?
思路 核心是事务启动时生成 ReadView,通过 undo log 版本链读取符合版本的记录,不读取事务启动后的新数据。
回答示例
InnoDB 的 MVCC 实现可重复读的核心是 ReadView(一致性视图)+ 版本链:
- 每个事务启动时,会生成一个 ReadView,包含三个核心值:
m_ids:当前活跃的事务 ID 列表;min_trx_id:活跃事务最小 ID;max_trx_id:下一个要分配的事务 ID;
- 每行数据都有隐藏列:
trx_id(修改该记录的事务 ID)、roll_pointer(指向 undo log 版本链); - 事务读取数据时,会遍历版本链,找到第一个满足“事务 ID < min_trx_id 或 事务 ID 不在 m_ids 中”的记录(即事务启动前已提交的数据);
- 整个事务期间,ReadView 不会变化,因此多次读取同一数据,都会拿到同一版本,实现“可重复读”。
4. synchronized 偏向锁在 JVM 里是怎么标记线程 ID 的?
思路 存储在对象头 MarkWord 中:偏向锁模式下,MarkWord 会记录偏向的线程 ID + 偏向锁标记位。
回答示例
偏向锁的线程 ID 存储在对象头的 MarkWord 区域,具体逻辑:
- 对象创建时,MarkWord 的偏向锁标记位为 1、锁状态位为 01,此时线程 ID 为 0(无偏向);
- 第一个线程获取偏向锁时,JVM 会通过 CAS 把该线程的 ID 写入 MarkWord 的“线程 ID 字段”,同时设置偏向时间戳;
- 后续该线程再次获取锁时,只需对比 MarkWord 中的线程 ID 是否与自身一致:一致则直接获取锁,无需 CAS/自旋;
- 若有其他线程竞争,偏向锁会撤销,升级为轻量级锁。
简单说:偏向锁把“专属线程 ID”写在对象头,通过 ID 匹配快速加锁,减少无竞争时的开销。
5. 轻量级锁自旋失败后为什么会膨胀为重量级锁?
思路 自旋消耗 CPU,且自旋次数有限,持续自旋会导致 CPU 空耗;重量级锁让线程阻塞,释放 CPU 资源。
回答示例
轻量级锁自旋失败膨胀为重量级锁的核心原因是避免 CPU 空耗:
- 轻量级锁的自旋是“忙等”:线程在用户态循环尝试 CAS 加锁,不释放 CPU 资源;
- JVM 对自旋次数有限制(默认 10 次或自适应自旋):若自旋次数耗尽仍未获取锁,说明竞争激烈;
- 此时继续自旋会大量消耗 CPU(多个线程空等),因此 JVM 会把轻量级锁膨胀为重量级锁:
- 调用 OS 内核的互斥锁(mutex),让失败的线程进入“阻塞态”,释放 CPU;
- 当锁释放时,通过内核唤醒阻塞的线程,虽然上下文切换有开销,但避免了 CPU 空耗。
核心权衡:轻量级锁适合“短时间、低竞争”,重量级锁适合“长时间、高竞争”。
6. 装饰器模式在 JDK 里的典型应用是什么?
思路 核心示例:IO 流(BufferedReader、InputStream 系列),通过装饰器动态增强流的功能。
回答示例
JDK 中装饰器模式最典型的应用是 Java IO 流,比如:
- 基础流:
FileInputStream(读取文件)、FileReader(字符读取); - 装饰器流:(缓冲增强)、(读取基本类型
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏在精不在多,内容分为八股文、大厂真实面经,面试通过后将offer和面试题私发给我,可退还专栏的收益部分费用。欢迎大家共建专栏

查看28道真题和解析