news 2026/4/30 8:47:58

孤舟笔记 并发篇五 乐观锁和悲观锁到底啥区别?面试为什么总爱问这对冤家

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
孤舟笔记 并发篇五 乐观锁和悲观锁到底啥区别?面试为什么总爱问这对冤家

文章目录

    • 先说结论:两种截然不同的"世界观"
    • 悲观锁:宁可错杀,不可放过
    • 乐观锁:先干了再说,冲突了我重试
    • 乐观锁的翻车现场:ABA 问题
    • 乐观锁 vs 悲观锁:到底选谁?
    • 乐观锁与悲观锁全景
    • 回答技巧与点评
        • 标准回答
        • 加分回答
        • 面试官点评

个人网站

你写代码的时候,有没有纠结过这个问题——多个线程要改同一份数据,到底该不该加锁?加了锁,性能差;不加锁,数据可能被改乱。更头疼的是,面试官总喜欢问"乐观锁和悲观锁的区别",你背了半天定义,一追问场景就懵了。

今天咱们就把这对"冤家"彻底拆开,看看它们各自在什么场景下能大显身手。

先说结论:两种截然不同的"世界观"

||| 维度 | 说明 |
|||------|------|
||| 悲观锁 | 认为冲突一定会发生,先锁再说 |
||| 乐观锁 | 认为冲突大概率不会发生,先干后验 |
||| 悲观锁实现 | synchronized、ReentrantLock |
||| 乐观锁实现 | CAS、版本号机制(Version) |
||| 悲观锁适用场景 | 写多读少、竞争激烈 |
||| 乐观锁适用场景 | 读多写少、竞争不激烈 |
||| 悲观锁缺点 | 阻塞等待,上下文切换开销大 |
||| 乐观锁缺点 | 冲突时自旋重试,消耗 CPU |

一句话记住:悲观锁像锁门上厕所,乐观锁像超市自助结账——先扫码,冲突了再重试。

悲观锁:宁可错杀,不可放过

想象你去一个只有一个坑位的公共厕所。进去第一件事干啥?锁门。你不会先看看有没有人来,再决定锁不锁——因为你假设随时可能有人来抢。

悲观锁就是这个思路:不管有没有冲突,我先拿到锁再说。没拿到锁的线程?排队等着,等锁释放了再来。

在 Java 里,synchronizedReentrantLock都是悲观锁的典型实现:

synchronized(lock){// 进入这段代码前,必须拿到锁 👈balance-=100;}

没有悲观锁会怎样?两个线程同时读到余额是 500,各自减 100,写回去都变成 400,凭空少了 100 块。这就是经典的"丢失更新"问题。

悲观锁的好处是简单粗暴、绝对安全。坏处也显而易见——如果 10 个线程只有 1 个要写,其他 9 个都在读,结果 9 个读线程也被堵在外面,这性能也太浪费了。

乐观锁:先干了再说,冲突了我重试

再看超市自助结账。你扫码付款的时候,不会先锁住整个货架——你假设大概率没人跟你抢同一个商品。先操作,提交的时候再检查有没有冲突。

乐观锁就是这个逻辑:先不管锁,直接改数据,提交时验证是否有其他线程改过。如果没有,提交成功;如果有,重试或者报错。

最常见的乐观锁实现方式有两种:

1. CAS(Compare And Swap)

AtomicIntegercount=newAtomicInteger(0);count.incrementAndGet();// 底层就是 CAS 👈// 比较:当前值是不是我读到的值?是→更新;不是→重试

2. 版本号机制(数据库乐观锁常用)

UPDATEaccountSETbalance=balance-100,version=version+1WHEREid=1ANDversion=5;👈-- 版本不对就更新失败

没有乐观锁会怎样?那就只能用悲观锁,即使 100 次操作只有 1 次冲突,也得每次都加锁。就像超市每次结账都要清场,太离谱了。

乐观锁的翻车现场:ABA 问题

乐观锁看起来很美,但它有个经典翻车场景——ABA 问题

假设线程 A 读到值是 1,准备 CAS 更新。这时候线程 B 把 1 改成 2,又改回 1。线程 A 一比较,值还是 1,CAS 成功了——但这个 1 已经不是原来的 1 了!

生活类比:你把一份文件放在桌上,去接了个电话。回来一看,文件还在原位——但你不知道中间有人拿走过,看了内容,又放回去了。

解决方案?用版本号,或者 Java 提供的AtomicStampedReference,给值加个"邮票",每次修改邮票 +1:

AtomicStampedReference<Integer>ref=newAtomicStampedReference<>(1,1);// 值1,版本1 👈// CAS 时同时比较值和版本号,杜绝 ABA

乐观锁 vs 悲观锁:到底选谁?

选锁的核心原则就一条:看竞争程度。

  • 写多读少,竞争激烈→ 悲观锁。因为冲突概率高,乐观锁会疯狂重试,CPU 自旋到怀疑人生。
  • 读多写少,竞争不激烈→ 乐观锁。大部分时候没有冲突,加锁纯属浪费性能。

一个常见误区:乐观锁一定比悲观锁快。错!如果冲突特别频繁,乐观锁的重试开销比加锁还大。就像堵车的时候,你非要走小路绕来绕去,结果每条小路都堵,还不如老老实实排大队。

实际项目中,很多框架已经帮你做了选择。比如 MyBatis-Plus 的@Version注解就是乐观锁,而synchronized是悲观锁,根据场景选用就行。

乐观锁与悲观锁全景

锁策略 全景 核心概念 ├── 悲观锁 ── 先锁后用,阻塞等待 │ ├── synchronized(JVM 层面) │ └── ReentrantLock(API 层面) └── 乐观锁 ── 先用后验,冲突重试 ├── CAS(Compare And Swap) ├── 版本号机制(Version) └── AtomicStampedReference(解决 ABA) 选择策略 ├── 写多读少 → 悲观锁 ├── 读多写少 → 乐观锁 └── 竞争激烈 → 悲观锁(避免自旋浪费) 口诀:悲观锁门防冲突,乐观扫码先做主, 写多用悲少用乐,ABA 问题版本补。

回答技巧与点评

标准回答

乐观锁和悲观锁是两种并发控制策略。悲观锁认为冲突一定会发生,操作前先加锁,确保独占访问,典型实现有 synchronized 和 ReentrantLock;乐观锁认为冲突大概率不会发生,先操作再验证,冲突时重试,典型实现有 CAS 和版本号机制。悲观锁适用于写多读少的场景,乐观锁适用于读多写少的场景。

加分回答
  1. 设计原则:乐观锁体现了"先假设最好情况"的设计思想,类似"宽容优先"策略;悲观锁体现了"防御优先"策略,两者本质是性能与安全的权衡
  2. ABA 问题与边界:乐观锁的 ABA 问题是经典陷阱,可用AtomicStampedReference或版本号解决。此外,乐观锁在极高并发下会导致大量自旋重试,反而比悲观锁性能更差——乐观锁不是银弹
  3. 实际应用:数据库层面,MyBatis-Plus 用@Version实现乐观锁,SELECT ... FOR UPDATE是悲观锁;分布式场景中,Redis 的WATCH/MULTI也是乐观锁思想
面试官点评

这道题考的是你对并发控制策略的理解深度和场景判断能力。只背定义"悲观锁加锁、乐观锁不加锁"只能拿及格分。能说清 ABA 问题、适用场景的权衡、以及在具体框架(如数据库、Redis)中的体现,才能拿高分。如果你还能指出"乐观锁不是银弹,高竞争场景反而更慢",面试官会眼前一亮。

原文阅读


内容有帮助?点赞、收藏、关注三连!评论区等你 💪

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/30 8:38:36

大模型应用开发:泡沫还是软件测试人员入局AI的最佳切入点?

测试工程师的AI转型焦虑与机遇2026年&#xff0c;AI大模型技术已深度渗透软件开发全流程。对软件测试从业者而言&#xff0c;自动化测试脚本生成、智能缺陷预测、用户行为仿真等AI应用场景的爆发&#xff0c;既带来职业替代焦虑&#xff0c;也创造了前所未有的转型机遇。当行业…

作者头像 李华
网站建设 2026/4/30 8:35:38

代码随想录算法训练营Day-38动态规划06 | 322. 零钱兑换、279.完全平方数、139.单词拆分、多重背包、总结

目录 322. 零钱兑换 动规五部曲 279.完全平方数 动规五部曲 为什么相比上一题不需要if判断 139.单词拆分 动规五部曲 多重背包 问题解释 代码的改动 总结 三种背包问题 两种递推公式 组合数与排列数 322. 零钱兑换 动规五部曲 1.dp[j]的含义是&#xff0c;凑齐…

作者头像 李华
网站建设 2026/4/30 8:33:23

ComfyUI-Manager:AI工作流管理的终极解决方案

ComfyUI-Manager&#xff1a;AI工作流管理的终极解决方案 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable various custom nodes …

作者头像 李华
网站建设 2026/4/30 8:32:38

压缩记忆召回系统:优化大型语言模型上下文管理

1. 项目概述&#xff1a;压缩记忆召回系统 在大型语言模型应用中&#xff0c;上下文记忆管理一直是个棘手问题。传统方案要么受限于token窗口导致历史信息丢失&#xff0c;要么因全量存储带来高昂计算成本。MyMories.mmr项目提出了一种创新解决方案——通过压缩记忆召回机制&am…

作者头像 李华