news 2026/3/31 10:27:32

锁、互斥、阻塞、自旋、CAS、可见性

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
锁、互斥、阻塞、自旋、CAS、可见性

今天的目标是:从 OS 视角理解“为什么必须有锁”、“为什么会出现竞态”、“锁为什么能解决”、“CAS 的本质是什么”。

这一层是并发编程最容易混乱的地方,因为它跨越:

  • OS 调度(Day3)

  • CPU 缓存一致性(你之前学到部分)

  • 用户态同步原语

Day4 只讲 OS 层和同步原语,不讲 CPU 内存模型(那是 Day5/Day6 的事)。

核心问题:

  • 为什么会有竞态条件(Race Condition)?(OS 层视角)

  • 为什么需要锁?锁解决了什么?

  • 锁的两种实现路径:阻塞锁 vs 自旋锁

  • 为什么需要 CAS?CAS 解决了什么?

今天的关键目标是:从OS的视角,把所有并发错误的根因定位到“共享 × 切换”。

依旧先看第一个问题:

为什么会有竞态?(这篇文章的根本逻辑)

在上一篇 调度器(Scheduler)与线程状态模型 中,我们曾学到:

  • CPU 随时可能切换线程

  • 多线程共享同一个进程的内存空间

容易得到以下事实:

共享内存 × 不确定时刻切换
= 访问顺序不可控
= 竞态的根因

本质不是“两个线程修改同一变量”
而是:

线程之间的执行交错是不可预测的。

OS 不会告诉你:

  • 会不会切

  • 什么时候切

  • 切到哪条指令之间

所以任何共享可变数据默认就会出现竞态。

这是锁存在的唯一天然理由。

为什么需要锁?锁解决了什么?

锁的出现不是为了解决“多线程修改同一变量”,
而是为了解决:

在临界区(critical section)内禁止调度器切走线程。

一个线程拿到锁后,它可以保证:

在退出锁之前,不会有其他线程进入这段代码

也就是:

锁是一个“对调度器的限制”。
它把某段代码变成原子的:要么执行完,要么没执行。

锁解决的问题是:

  • 两个线程同一时间进入临界区

  • 两个线程交错执行导致状态错乱

  • 读—改—写操作被打断

但是显然还有其他问题,比如:

  • 内存可见性(CPU 层)

  • 缓存传播(后面讲)

  • 语义保证(事务级别)

在这里只讲OS视角。

接下来先看看两类锁:

阻塞锁 vs 自旋锁

调度器是如何配合锁的?
阻塞(Block)自旋(Spin)两种行为。

① 阻塞锁:拿不到锁 → 线程进入 Blocked

流程如下:

Thread A 拿到锁

Thread B 来抢锁

锁不可用 → OS 把 Thread B 扔进 Blocked 状态

Thread A 释放锁 → OS 唤醒 B

特点:

  • 线程让出 CPU(节省 CPU 资源)

  • 唤醒需要调度器参与(慢)

  • 适合持锁时间较长的场景

② 自旋锁:拿不到锁 → 线程疯狂检查锁状态(不让出 CPU)

比如:

while (!lock_available) { // spin }

特点:

  • 不进入 Blocked,不让出 CPU

  • 快速检查锁是否可用

  • 若锁很快释放,自旋比阻塞快得多

  • 若锁很慢释放 → 自旋浪费 CPU

CAS 的本质是什么?为什么需要它?

CAS(Compare-And-Swap)的本质是一条CPU 提供的原子指令

if (*addr == expected) { *addr = new; return success; } else { return fail; }

CAS解决的问题不是锁太慢,而是:

需要一种无需进入内核态、不触发调度、不阻塞线程的原子更新方式。

CAS 的特点:

  • 不进入内核态(用户态完成)

  • 不进 Blocked(无调度切换)

  • 无需锁(lock-free)

  • 失败了就重试(loop)

即:

CAS 是构建“无锁算法”的最小原子粒度。

一句话总结,就是:

锁(阻塞、自旋)与 CAS 都是在补偿“共享 × 不确定切换”导致的竞态不可避免性。

继续看五道问题:

Q1:为什么会产生竞态?(一句话)

Q2:锁的本质作用是什么?(一句话)

Q3:阻塞锁与自旋锁的区别是什么?(一句话)

Q4:CAS 的本质是什么?为什么需要它?(一句话)

Q5:为什么有了 CAS 还需要锁?

原思路:

Q1,单论OS层面,因为CPU随时可能切换线程,多线程共享同一个进程的虚拟空间,导致线程之间的执行顺序不可预测
Q2,防止可变共享数据出现竞态
Q3,
Q4,CAS的本质是一条CPU提供的原子指令,为了线程无需进入内核态,不触发调度,不阻塞其他线程
Q5,因为CAS无法根治竞态关系,他只能尽可能的不阻塞其他线程

标准答案:

Q1:线程共享内存且 CPU 可在任意时刻切换执行流,导致执行顺序不可控。

Q2:限制调度,使同一时间只有一个线程能进入临界区。

Q3:阻塞锁失败会让线程进入 Blocked 并让出 CPU;自旋锁失败会忙等而不让出 CPU。
Q4:CAS 是 CPU 提供的原子指令,用于在用户态实现无锁的原子更新
Q5:CAS 只能原子操作单个变量,无法保护复杂临界区。

最终模型:

① 竞态产生于线程共享内存且 CPU 可在任意时刻切换执行流,导致执行顺序不可控。

② 锁的本质作用是限制调度,使同一时间只有一个线程能够进入临界区。

③ 阻塞锁获取失败会让线程进入 Blocked 并让出 CPU;自旋锁获取失败会忙等而不让出 CPU。

④ CAS 是 CPU 提供的原子比较并交换指令,用于在用户态完成无锁的原子更新。

⑤ CAS 只能原子操作单个变量,复杂或长临界区仍必须依赖锁来保证互斥。

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

两相液体冷却如何解决热管理危机

数据中心正面临着日益严重的散热危机,因为AI工作负载产生的热量水平已经超出了传统空气冷却系统的处理能力。机架密度现在已超过70千瓦——这在几年前是难以想象的——这一日益严峻的挑战推动了热管理策略的根本性转变。两相液体冷却曾经仅限于专门的高性能计算环境…

作者头像 李华
网站建设 2026/3/30 20:44:37

笑不活!男人假装爱你,7 个 “演技信号” 速查!

和异性勾肩搭背不避嫌,边界感直接喂了狗!承诺说得斩钉截铁,转头就忘像没说过!听你说事儿超敷衍,耐心比指甲盖还短!嘴上记得你喜好,买东西永远踩反坑!给杯奶茶都要念叨,付…

作者头像 李华
网站建设 2026/3/19 5:15:51

基础电路记录

电路 倍压整流电路 这种电路可以将低压放大,但是电流比较小 适合:电蚊拍等 二倍压整流电路![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/ebc93f2d432744f79fcd2a297bf7d753.png也就是两个电池 三倍压整流电路全波整流桥式整流三极管自激震荡…

作者头像 李华
网站建设 2026/3/16 1:52:14

ABINIT能带计算数据处理脚本

前情提要:ABINIT入门教程三:Si的结构优化与能带结构计算 能带的数据保存在.agr格式文件夹中,可通过abipy或者xmgrace等软件读取,在Xmgrace中也可与直接导出数据,如无法安装Xmgrace则可依赖本文脚本则直接跳过其他软件直…

作者头像 李华
网站建设 2026/3/26 9:08:48

【Java毕设全套源码+文档】于 SpringBoot的干洗店预约洗衣系统的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/3/24 22:15:07

【Java毕设全套源码+文档】基于java的快递业务管理系统的设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华