java面试记录: sychonized 锁,熔断组件,分布式锁

宇信科技面试 --- Java问题复盘

这场面试几乎全是Java问题,正好暴露了你在传统后端方向上的一些真实水平。整体来看,你的表现不稳定 ------有的问题(技术框架、SAGA事务、Linux命令)回答得不错,但一到底层原理非常规方案就明显卡壳。下面逐一拆解。

一、分布式锁(MySQL实现方式)------ 没接触过 ≠ 可以不知道

你的回答

"用Redis来做分布式锁,结合MySQL做一个唯一索引起幂等作用。单独用MySQL做分布式锁,我这边没有遇到真实的开发场景。"

问题所在

面试官问"如果用MySQL做分布式锁怎么做",你回答"用Redis做"然后说自己没遇到过MySQL的场景。

这个回答的问题不是"不知道",而是你没有尝试用已有知识去推导,直接放弃了回答。

面试官为什么要问这个?因为分布式锁是高频考点 ,而MySQL实现是其中最简单的方案之一------它不需要引入Redis,纯数据库就能做。他不期望你实际用过,但期望你知道有这几种方案并说出思路。

正确答案

MySQL做分布式锁主要有三种方式:

方案 实现方式 优缺点
唯一索引 + INSERT 建一张lock表,锁名设为唯一索引;获取锁时INSERT,释放时DELETE 简单,但无超时机制,释放锁失败会死锁;需要心跳保活线程
SELECT ... FOR UPDATE 利用行锁,同一时刻只有一个线程能获取到锁 依赖事务,锁会随事务提交释放;有超时机制,但性能一般
GET_LOCK() MySQL内置的GET_LOCK(str, timeout)函数 纯数据库方案,支持超时,但只适用于同一连接;MySQL不同版本行为有差异,生产中使用较少

简单示例(方式一):

sql 复制代码
-- 1. 建一张锁表
CREATE TABLE distributed_lock (
    lock_key VARCHAR(64) PRIMARY KEY, -- 唯一索引
    owner VARCHAR(64),
    expire_time DATETIME
);

-- 2. 获取锁(INSERT成功即获得锁)
INSERT INTO distributed_lock (lock_key, owner, expire_time) 
VALUES ('order_lock', 'instance_001', NOW() + INTERVAL 30 SECOND);
-- 如果INSERT失败(主键冲突),说明锁被占用

-- 3. 释放锁
DELETE FROM distributed_lock WHERE lock_key = 'order_lock' AND owner = 'instance_001';
-- 必须带上owner,避免释放了别人的锁

即使没实际做过,也可以这样说:

"我没在项目里用MySQL做过分布式锁,但我们用的是Redis + Redisson。但如果用MySQL实现的话,我知道可以用一张锁表加唯一索引,通过INSERT成功与否来判断锁获取结果;也可以用SELECT ... FOR UPDATE来实现排他锁。不过相比Redis,MySQL方案的性能要差一些,我们当时没选它。"

二、synchronized底层原理------回答太浅

你的回答

"它是一个独占锁、悲观锁,线程锁上之后有互斥性,直到线程执行完释放,别的线程才能获取。"

问题所在

这个回答只停留在表象层面,没有触及任何底层机制。面试官问"底层原理"时,期望你至少讲到:

  1. monitor(监视器) 的概念
  2. 对象头(Mark Word) 中的锁状态
  3. 锁升级(偏向锁 → 轻量级锁 → 重量级锁)

你说的"独占锁、悲观锁"是ReentrantLock也有的特征,没有说出synchronized的独特性。

正确答案

text 复制代码
synchronized底层基于JVM的monitor(监视器)机制实现。

每个Java对象都有一个对象头(Mark Word),其中记录了锁的状态。
当线程进入synchronized代码块时,它会尝试获取该对象的monitor:
- 成功 → 进入代码块,monitor计数器+1(可重入)
- 失败 → 线程阻塞,等待锁释放

JDK 1.6之后引入了锁升级机制(偏向锁 → 轻量级锁 → 重量级锁):
- 偏向锁:只有一个线程访问时,Mark Word记录该线程ID,无需CAS操作
- 轻量级锁:多个线程交替访问时,使用CAS自旋尝试获取锁
- 重量级锁:竞争激烈时,升级为操作系统互斥量(Mutex),线程阻塞,涉及用户态/内核态切换

释放锁时,monitor计数器减为0,唤醒等待线程。

最低底线: 即使背不全,至少说出"基于对象头的Mark Word"、"有锁升级机制"、"偏向锁→轻量级锁→重量级锁"这三个关键词,面试官就知道你了解底层。

三、线程池资源管控------关键词不全

你的回答

"核心线程数、最大线程数、空闲时间、队列、拒绝策略。CPU密集型的线程数=CPU数+1。"

问题所在

回答的基本正确,但太简略了 。面试官问的是"资源管控涉及哪些因素",你只列了参数名,没有展开说明为什么这些参数重要、如何合理配置

另外"CPU数+1"是常见公式,但你没说清楚:

  • I/O密集型应该怎么配?
  • 核心线程数和最大线程数之间的差值意味着什么?

补充回答

text 复制代码
线程池资源管控主要涉及以下因素:

1. 核心参数配置(corePoolSize / maxPoolSize / keepAliveTime / workQueue / handler)

2. 线程数的估算:
   - CPU密集型:核心线程数 = CPU核数 + 1(减少上下文切换)
   - I/O密集型:核心线程数 = CPU核数 × 2(或更大,因为线程大部分时间在等待I/O)
   - 混合型:可以用公式:线程数 = CPU核数 × (1 + 等待时间/计算时间)

3. 队列选择:
   - 无界队列(LinkedBlockingQueue):可能导致OOM,不推荐
   - 有界队列(ArrayBlockingQueue):控制资源消耗,配合拒绝策略

4. 拒绝策略:
   - AbortPolicy(默认):抛异常
   - CallerRunsPolicy:用调用者线程执行(削峰)
   - DiscardPolicy / DiscardOldestPolicy:丢弃(谨慎使用)

5. 监控与动态调整:
   - 通过线程池提供的监控方法(getActiveCount、getQueueSize)观察运行状态
   - 配合Apollo/Nacos实现动态参数调整

四、熔断实现原理------知道组件但说不清原理

你的回答

"通过滑动窗口组件,检测慢调用比例和异常比例,超过比例就触发open模式。"

问题所在

提到了"滑动窗口"和"open模式",说明你知道Sentinel/Hystrix的概念,但没有把完整流程讲清楚,显得支离破碎。

正确答案

text 复制代码
熔断的核心原理是:在固定时间窗口内统计请求的失败率,超过阈值则触发熔断,后续请求快速失败,避免级联故障。

以Sentinel为例,它使用滑动窗口(多个时间片组成一个窗口)来统计每个时间片内的请求数、异常数、响应时间等指标。

状态机:
┌─────────┐
│ CLOSED  │ ------ 正常运行,统计失败率
│ (关闭)  │
└────┬────┘
     │ 失败率超过阈值
     ▼
┌─────────┐
│  OPEN   │ ------ 熔断开启,所有请求直接快速失败
│ (开启)  │
└────┬────┘
     │ 等待sleepWindow时间后
     ▼
┌─────────┐
│HALF-OPEN│ ------ 放行少量请求探测,成功则恢复CLOSED,失败则回到OPEN
│(半开)   │
└─────────┘

关键参数:
- 统计时间窗口(statIntervalMs):统计多久的数据
- 失败率阈值(failureRateThreshold):超过多少比例触发熔断
- 熔断恢复时间(sleepWindowMs):熔断后多久尝试恢复

提醒: 你答"open模式"时,如果能补上"CLOSED → OPEN → HALF-OPEN"这个状态机转换,面试官对你的评价会明显提升。

五、分布式锁(zk / etcd)------ 你完全没提,但面试官可能默认你知道

背景

虽然面试官没追问"除了Redis和MySQL还有没有其他方案",但如果他接着问,你很可能也答不上来。

补充知识

方案 实现方式 优点 缺点
Redis(Redisson) SET NX + 过期时间 + 看门狗 高性能、可自动续期 依赖Redis稳定性、主从切换可能丢锁
ZooKeeper 创建临时顺序节点,序号最小的获得锁 强一致性、支持Watch机制 性能不如Redis、需维护ZK集群
etcd Lease + Revision机制 强一致性、高性能 运维成本较高
MySQL 唯一索引 / SELECT FOR UPDATE 简单,无需额外中间件 性能差、依赖数据库

面试场景模拟:

"除了Redis和MySQL,你还知道哪些分布式锁的实现方式?"

你可以这样答:

"还有ZooKeeper和etcd。ZooKeeper是利用临时顺序节点,序号最小的节点获得锁,配合Watch机制监听前一个节点的释放事件。etcd类似,利用Lease租约和Revision版本号来实现。这两种方案都提供强一致性,但性能不如Redis,一般用于对一致性要求极高的场景。"

如果你没实际用过,这段话至少证明你知道这些方案的存在和基本思路

六、其他小问题

1. "核⼼线程数=CPU数+1"这个公式只适用于CPU密集型

你在回答中提到了这个公式,但没有说明前提条件 ------这个公式只适用于纯CPU密集型 任务。如果是I/O密集型 (比如数据库查询、HTTP调用、文件读写),线程数需要更大,通常用 CPU核数 × 2CPU核数 × (1 + 等待时间/计算时间)

2. 记账业务讲清楚了,但缺少"对账"环节

你在讲记账流程时说了MQ发送账务数据给总账模块,但没有提对账 。银行系统记账的核心目标之一是账务平衡(总账 = 各核心子系统账务之和)。如果面试官追问"你怎么确保账最终是平的?"你可能会卡住。

备一个回答:

"除了实时记账外,我们每天日切后会跑一个对账批处理,把贷款核心、存款核心的流水和总账做一次汇总比对,发现差额会生成对账差异报告,人工介入处理。"

七、关于出差和加班 ------ 你的表达可以更职业

你的回答

"周末加班有加班费吗?" → "没有。" → "那行吧。"

"出差补助的标准是多少呢?" → 追问了两次

问题所在

问薪资福利完全没问题,这是你的权利。但你的问法有点"直接在谈判桌上掀底牌"的感觉------"没有加班费,那行吧"这种语气容易让面试官觉得你比较计较。

建议的表达方式

"关于加班和出差,我这边可以接受。我之前在银行驻场也经历过上线冲刺,连续一两周加班到很晚的情况都有。只是我这边刚结婚,如果出差周期太长,希望中间能有回西安的机会。具体的补贴和调休政策,我后面再跟HR详细了解一下。"

核心差异:

  • 你先表达接受 ,再提诉求 (回家的机会、调休),最后说细节问HR
  • 这样既维护了自己的权益,又不会让面试官觉得你"还没入职就在讨价还价"

八、综合判断

通过概率

这场面试的难度明显低于前两场,面试官问的大多是标准八股题。你的表现中规中矩------该答的答上了(SAGA、技术框架、Linux命令),该露怯的也露了(synchronized底层、MySQL分布式锁、熔断原理不完整)。

好消息是:这些问题都可以短期突击解决

本场暴露的核心短板(按严重程度)

排序 知识点 建议行动
1 synchronized底层原理 背熟"对象头Mark Word → 锁升级(偏向→轻量→重量)→ monitor"这条线
2 MySQL分布式锁的三种实现 能说出唯一索引+INSERT / FOR UPDATE / GET_LOCK即可应急
3 熔断原理(状态机) 背熟CLOSED → OPEN → HALF-OPEN三态流转
4 线程池完整参数配置 把CPU密集/I/O密集的公式和队列选择逻辑记清楚
5 分布式锁方案全景(Redis/MySQL/ZK/etcd) 知道每种方案的存在和适用场景,下次被追问不会措手不及

短期冲刺建议(3天内)

  1. synchronized底层:把对象头结构、锁升级过程讲一遍录下来,听到自己流利为止
  2. MySQL分布式锁:把建表SQL和获取/释放逻辑写在备忘录里,面试前看一遍
  3. 熔断三态:画一遍状态图,确保自己能顺着箭头讲完整个流程

Java基础部分只要这3个点补上,你下次再面Java岗位,体感会完全不同。

相关推荐
有颜有货1 小时前
PMC生产排产的4种算法,一次讲清
java·服务器·前端
lilihuigz2 小时前
Meta Box完整指南:WordPress自定义字段与内容框架高效构建结构化内容 - 易服客工作室
java·开发语言
xxie1237942 小时前
Python 闭包的调用方法与实践
开发语言·python
aini_lovee2 小时前
计算 HOG算子的典型 MATLAB 程序
开发语言·matlab
楷哥爱开发2 小时前
降低网络爬虫成本:基础设施优化指南
服务器·开发语言·php
贺国亚2 小时前
AI制品Registry与发布门禁
面试
尚早立志2 小时前
Spring Boot 源码研读之ConfigurableEnvironment 环境准备
java·spring boot·后端
YuK.W2 小时前
Leetcode100: 94.二叉树中序遍历、104.二叉树最大深度、226.翻转二叉树
java·算法·leetcode·二叉树
乂爻yiyao2 小时前
0. openems 部署与体验
java·openems