并发编程里的"堵车"与"红绿灯":死锁、活锁与两种锁策略(乐观锁、悲观锁)

搞后端或者数据库开发,永远绕不开"资源争抢"这个问题。

今天把这几个老生常谈的概念------死锁、活锁、悲观锁、乐观锁,放在一起捋一捋。前两个是"事故现场",后两个是"交通规则"。一起学习一下


一、 事故现场:当线程打起来了

1. 死锁 (Deadlock):互不相让

这是最常见的"事故"。说白了就是:也就是你也动不了,我也动不了,大家都耗着。

真实场景 : 你有两个资源:OrderTable(订单表)和 StockTable(库存表)。

  • 线程 A:锁住了 OrderTable,准备去扣减 StockTable
  • 线程 B:锁住了 StockTable,准备去写入 OrderTable

结果就是:A 拿着 B 想要的东西,B 拿着 A 想要的东西,谁都不撒手。

代码模拟(伪代码)

csharp 复制代码
// 错误的加锁顺序导致死锁
​
// 线程 1
async function transactionA() {
  await lock('Order'); // 拿到了 Order 锁
  await sleep(100);    // 稍微慢一点,等线程 2 锁住 Stock
  await lock('Stock'); // 此时卡住,因为 Stock 被线程 2 锁了
}
​
// 线程 2
async function transactionB() {
  await lock('Stock'); // 拿到了 Stock 锁
  await sleep(100);
  await lock('Order'); // 此时卡住,因为 Order 被线程 1 锁了
}

怎么解? 最简单的解法是定规矩 :所有人必须按照相同的顺序拿锁。比如规定"必须先拿 Order 再拿 Stock",死锁瞬间就解了。

2. 活锁 (Livelock):过分礼让

活锁比较隐蔽,它不会卡死,但就是干不成事。

真实场景: 两人在走廊迎面相遇。

  • 你往左躲,他也往左躲(撞)。
  • 你赶紧往右躲,他也往右躲(又撞)。
  • 你们俩一直在动,CPU 也就是一直在忙(出汗了),但谁也没过去。

代码里的表现: 通常发生在处理消息队列或者重试机制里。 比如一个任务处理失败了,系统立刻重试,又失败,又立刻重试... 资源一直在消耗,日志一直在打,但任务永远处于"处理中"。

怎么解? 引入随机性。以太网的"指数退避算法"就是这个原理:撞了之后,不要立刻重试,你等 10ms,我等 50ms,错峰出行。


二、 交通规则:怎么防止出事故?

为了防止上面那种乱套的情况,我们需要锁。根据"心态"的不同,分成了悲观乐观两派。

1. 悲观锁 (Pessimistic Locking)

心态:"这世界坏人多,总有人想抢我的数据。也就是我操作的时候,谁也别想动!"

做法: 在查数据的时候,直接把数据锁死,直到我提交事务,别人才能查或改。

2. 乐观锁 (Optimistic Locking)

心态:"这世界还是好人多,大部分时候没人跟我抢。我就先跑着,最后检查一下就行。"

做法 : 我不锁数据,大家都随便读、随便改。但是!我在更新的那一瞬间,会检查一下: "这数据自从我读走之后,有没有被人改过?"

实现方式(CAS / 版本号) : 给表加一个 version 字段。

ini 复制代码
-- 1. 先查出来,假设拿到 version = 1
SELECT id, stock, version FROM goods WHERE id = 1;
​
-- 2. 内存里计算 stock - 1
​
-- 3. 更新时,带上版本号做条件
UPDATE goods 
SET stock = stock - 1, version = version + 1 
WHERE id = 1 AND version = 1; 
-- 关键在这里!如果 version 已经被别人改成 2 了,这条 SQL 影响行数就是 0,更新失败。
  • 优点:快!没有锁等待,大家都能读,并发能力强。
  • 缺点:如果竞争真的很激烈(比如抢火车票),会一直失败重试,CPU 可能会飙高。

如果你觉得这篇文章有帮助,欢迎关注我的 GitHub,下面是我的一些开源项目:

Claude Code Skills (按需加载,意图自动识别,不浪费 token,介绍文章):

全栈项目(适合学习现代技术栈):

  • prompt-vault - Prompt 管理器,用的都是最新的技术栈,适合用来学习了解最新的前端全栈开发范式:Next.js 15 + React 19 + tRPC 11 + Supabase 全栈示例,clone 下来配个免费 Supabase 就能跑
  • chat_edit - 双模式 AI 应用(聊天+富文本编辑),Vue 3.5 + TypeScript + Vite 5 + Quill 2.0 + IndexedDB
相关推荐
NPE~4 小时前
自动化工具Drissonpage 保姆级教程(含xpath语法)
运维·后端·爬虫·自动化·网络爬虫·xpath·浏览器自动化
五月君_4 小时前
炸裂!Claude Opus 4.6 与 GPT-5.3 同日发布:前端人的“自动驾驶“时刻到了?
前端·gpt
Mr Xu_4 小时前
前端开发中CSS代码的优化与复用:从公共样式提取到CSS变量的最佳实践
前端·css
宋小黑5 小时前
JDK 6到25 全版本网盘合集 (Windows + Mac + Linux)
java·后端
鹏北海-RemHusband5 小时前
从零到一:基于 micro-app 的企业级微前端模板完整实现指南
前端·微服务·架构
LYFlied5 小时前
AI大时代下前端跨端解决方案的现状与演进路径
前端·人工智能
念何架构之路5 小时前
Go进阶之panic
开发语言·后端·golang
光影少年5 小时前
AI 前端 / 高级前端
前端·人工智能·状态模式
一位搞嵌入式的 genius5 小时前
深入 JavaScript 函数式编程:从基础到实战(含面试题解析)
前端·javascript·函数式
先跑起来再说5 小时前
Git 入门到实战:一篇搞懂安装、命令、远程仓库与 IDEA 集成
ide·git·后端·elasticsearch·golang·intellij-idea