news 2026/10/28 11:25:35

菜鸟要知道的「线程安全」

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
菜鸟要知道的「线程安全」

菜鸟要知道的「线程安全」

🤫本文基于go技术栈进行解释相关概念及部分源码展示~

✨线程安全是什么东西

线程安全,就是在多个线程并发操作同个资源的时候,产生的数据始终一致。

下面这个就是就是一个线程安全问题的例子:

var count int var wg sync.WaitGroup func main() { wg.Add(2) go func() { defer wg.Done(); for i := 0; i < 1000; i++ { count++ } }() go func() { defer wg.Done(); for i := 0; i < 1000; i++ { count++ } }() wg.Wait() fmt.Println(count) // 期望 2000,实际可能是 1800、1950 等任意值 } //count++ 不是原子操作(读 → 加1 → 写),多个 goroutine 交错执行会导致丢失更新。

解决办法有很多,最常见的就是加锁,同一时间只允许有一个线程可以对资源进行操作。
详细的代码在此不再作再多展示,因为我们本次的目的是研究:为什么加锁可以保证线程安全?

✨为什么加锁可以保证线程安全?

🧐吾日三省吾身

  • ⚠️是什么决定了多线程会出现不安全的情况?
  • ⚠️加锁实际上是如何保证线程安全?
  • ⚠️加锁转成底层指令会是怎么样?

🧐我们把问题拆解,逐步分析,再重新思考

🎯是什么决定了多线程会出现不安全的情况?
📔对资源的并发操作

🌰比如:一个简单修改变量的操作,转化成底层的汇编指令时,会生成多个指令。

汇编指令:读取-计算-写入 0x0000 MOVQ "".counter(SB), AX ; 读取当前值 0x0007 LEAQ 1(AX), CX ; 计算新值 (AX + 1) 0x000b MOVQ CX, "".counter(SB) ; 写回新值

如果不加锁的情况下,就会出现以下情况:

协程1协程2协程3
读取a=1读取a=1读取a=1
a++
写入a=2a++
a++
写入a=2写入a=2

解决:语言层面加入锁去确保多线程时同一时间只允许其中一个线程对资源进行

📔内存可见性

这里篇幅稍微涉及到的知识可能会稍微有点多,请耐心阅读!

在多核CPU的架构下,进程内的不同线程可能会被运行在不同的CPU核心中。
N个核心就代表这个CPU可以同时运行N个线程。

🖥️ 现代计算机的存储层次结构(从快到慢)

CPU 寄存器 ↓ L1 缓存(每个核心私有,~1ns) ↓ L2 缓存(每个核心私有或共享,~3ns) ↓ L3 缓存(所有核心共享,~10ns) ↓ 主存 RAM(~100ns) ↓ 磁盘 / SSD

看到这里就可以想到一个糟糕的事情:

线程A修改了变量a,但是一般情况下为了加快执行效率
CPU不会每次把数据写到L3或RAM中,而是会先写入L2或L1缓存中,然后发送失效广播给其他核心。(不保证马上处理)
所以运行在其他核心的线程读取变量a时,可能读到的是旧值,或者新值。

这会导致一个问题,只有当前线程或执行在该核心的线程能保证百分百读到更新后的值。

📔内存屏障

这里引入了一个「内存屏障」的概念,去解决内存可见性问题



内存屏障是“同步指令”,作用类似于操作数据库开始事务的命令,执行了内存屏障指令后,后续的指令会被内存屏障指令影响,功能可以分为三点:

  • 告诉 CPU:“把你缓存里的脏数据刷到主存!”
  • 告诉其他 CPU:“我刚刚更新了数据A,请把你们的数据A标记为过期!”
  • 告诉编译器/CPU:“别重排我屏障前后的代码!”

让更新了数据的CPU的脏数据刷到主存!

这里就是刚刚说到的,CPU操作数据时,不会直接把数据更新回主存,而是直接操作CPU的三级缓存,因为这样效率更高。
最后如果缓存数据满了,会采用淘汰算法,把淘汰的脏数据刷回主存中。

这里大家可能会有一个疑问:

❓为什么不直接更新到L3缓存就可以了?反正L3是所有核心的共享缓存。

现代的服务器一般都会有多个CPU插槽,每个CPU之间的L3是不可以互相访问的,所以要把更改的数据刷回主存才能让所有的CPU能找到最新的数据。

我刚刚更新了数据A,请把你们的数据A标记为过期!

当核心0修改了数据后并启用了内存屏障命令

mov [x], 1 ; 写入 x = 1(先写入 Core0 的 store buffer / cache) mfence ; 内存屏障

缓存一致性协议(如 MESI)被触发:

  • Core 0 的缓存行状态变为Modified (M);
  • 如果其他核心(如 Core 1)的缓存中有x的副本(状态为 Shared 或 Invalid),
    Core 0 会广播 “Invalidate” 消息;

Core 1 收到 Invalidate 后:

  • 将自己缓存中x的副本标记为Invalid (I);
  • 下次读x时,发现缓存行无效 → 触发 cache miss → 从其他核心的缓存或主存加载最新值(优先从其他核心读取)。

别重排我屏障前后的代码!

这里涉及到的是「指令重排」的问题
因为一般情况下,编译器会自己优化编排命令的执行顺序。

a := true b := "" go func() { b = "msg" a = false }() for a { } println(b) //打印结果有可能为空 //原因:编译器对指令进行了优化重新编排b="msg"被安排在a=false之后

这里可以理解为:
晚上去大排档吃夜宵,你点了一份炒面,另外有两个客人点了两份炒粉。老板可能会优先把两份炒粉一起炒了先,再安排炒面。
但是老板也有可能是个守规矩的人,先把你的炒面炒了,再给其他两个客人炒粉。
所以最终的结果取决于老板当时的想法。

✨总结

线程安全是什么?

确保多个线程访问同个资源最终结果的一致性。

怎么保证线程安全?

加锁&依赖内存屏障。保证同一资源同时操作的线程只有一个和解决「内存可见性」&「指令重排问题

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

计算机毕业设计springboot在线小说阅读平台 基于 SpringBoot 框架的网络小说阅读网站设计与实现 SpringBoot+Vue 架构在线小说阅读系统的开发与应用

计算机毕业设计springboot在线小说阅读平台3jzlz7ep &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。随着互联网技术的飞速迭代和数字阅读市场的蓬勃发展&#xff0c;传统纸质阅读…

作者头像 李华
网站建设 2026/10/20 9:43:50

同一堆模型、同一张贴图,换个 Shader 为啥就能“变脸”?——用大白话拆穿这些外观魔法的底层逻辑

你有没有这种体验: 同一个角色模型、同一张贴图,换个 Shader——哎哟,立马像换了一个人: 一秒变“金属盔甲”,再一秒变“塑料玩具”,再来个“玻璃雕像” 皮肤突然柔柔的、有点透光;头发的高光像打了发蜡 地面变水面,波光粼粼还会反射天空 火焰烧起来、冰面发亮、还带点…

作者头像 李华
网站建设 2026/10/21 13:00:09

内网环境下,如何使用js处理大文件的目录结构上传?

大文件上传方案设计与实现&#xff08;政府信创环境兼容&#xff09; 方案背景 作为北京某软件公司的开发人员&#xff0c;我负责为政府客户实现一个兼容主流浏览器和信创国产化环境的大文件上传系统。当前需求是支持4GB左右文件的上传&#xff0c;后端使用PHP&#xff0c;前…

作者头像 李华
网站建设 2026/10/23 17:10:22

冗余告警:企业应如何设置冗余标准、告警通道与阈值超限监控机制

设定网络设备冗余标准、打通告警通道、监控超出阈值事件 摘要 本文为企业IT部门、信息化负责人及运维团队提供可落地的冗余告警管理方案&#xff0c;通过标准化的网络设备冗余配置、打通全链路告警通道、搭建阈值超限监控机制&#xff0c;支撑系统规划、标准化交付与平台化运…

作者头像 李华
网站建设 2026/10/28 14:00:35

一键生成,全程优化:探索PaperRed ai论文写作助手的智能流水线创作

对于高校学生、科研从业者来说&#xff0c;论文写作本不必是孤军奋战的煎熬——从选题定框架到终稿优化定稿&#xff0c;每个环节的繁琐内耗&#xff0c;都能被AI智能流水线一键破解。PaperRed AI以“一键生成全程优化”为核心&#xff0c;打破传统论文写作的碎片化壁垒&#x…

作者头像 李华
网站建设 2026/10/22 3:52:25

Java 面试题及答案整理(2026年最新版)

2026年快到了&#xff0c;发现网上很多 Java 面试题都没有答案&#xff0c;所以花了很长时间搜集整理出来了这套 Java 面试题大全~这套互联网 Java 工程师面试题包括了&#xff1a;MyBatis、ZK、Dubbo、EL、Redis、MySQL、并发编程、Java 面试、Spring、微服务、Linux、Springb…

作者头像 李华