新闻详情

新闻详情

首页 / 资讯中心 / 详情

并发编程(五):Atomic——语言层的原子性、可见性与有序性

发布时间:2026/9/29 11:03:10来源:尧图网络
并发编程(五):Atomic——语言层的原子性、可见性与有序性
目录0. 从上一篇继续1. 三种语言的 Atomic 规则分别保证什么1.1 JavaAtomicInteger1.2 Gosync/atomic1.3 CPython应用层没有对称的 Atomic API2. 下一篇Atomic 是怎么实现的0. 从上一篇继续这一篇直接从语言内存模型层的规则讨论 Atomic。1. 三种语言的 Atomic 规则分别保证什么1.1 JavaAtomicInteger1.1.1 AtomicityAtomicInteger.incrementAndGet()原文“Atomically increments the current value, with memory effects as specified byVarHandle.getAndAdd.”这句话直接说明incrementAndGet()是一次原子加一。读取旧值、加一、写回不是三个可以被其他线程插入的步骤而是一次不可分割的 Atomic RMW。例如AtomicIntegercounternewAtomicInteger(0);// Thread Acounter.incrementAndGet();// Thread Bcounter.incrementAndGet();两次更新会依次作用在同一个值上Thread A Thread B incrementAndGet() incrementAndGet() │ │ ▼ ▼ 0 → 1 1 → 2因此不会出现普通counter中两个线程都读到0最后都写回1的丢失更新。1.1.2 VisibilityincrementAndGet()的内存效果由VarHandle.getAndAdd定义。VarHandle.getAndAdd 对写入的描述是“with the memory semantics ofsetVolatile(Object...)”而AtomicInteger.get()使用的是VarHandle.getVolatile的读语义。JLS §17.4.4 Synchronization Order 对 volatile 的规则是“synchronizes-with all subsequent reads of v by any thread”意思是Atomic 更新中的 volatile 写与另一个线程后续的 volatile 读之间可以建立synchronizes-with关系。放回前面的例子AtomicIntegercounternewAtomicInteger(0);booleanreadyfalse;// Thread Areadytrue;// A1counter.incrementAndGet();// A2// Thread Bif(counter.get()1){// B1System.out.println(ready);// B2}假设 B 的counter.get()读到的1就是 A 这次更新产生的结果那么Thread A Thread B A1 ready true │ │ program order ▼ A2 counter.incrementAndGet() │ │ synchronizes-with │ JLS §17.4.4 └──────────────────────────► B1 counter.get() 1 │ │ program order ▼ B2 read ready因此A 在 Atomic 更新之前已经完成的ready true对 B 后续的读取可见。这就是这里的Visibility。1.1.3 OrderingJLS §17.4.5 Happens-before Order 原文“If one action happens-before another, then the first is visible to and ordered before the second.”意思是happens-before 不只说明“能看见”还规定了两个操作之间必须遵守的先后关系。上面的例子可以直接推成A1 ready true ↓ program order A2 counter.incrementAndGet() ↓ synchronizes-with B1 counter.get() 1 ↓ program order B2 read ready也就是A1 happens-before A2 A2 happens-before B1 B1 happens-before B2 ↓ transitivity A1 happens-before B2所以 B 一旦已经通过counter.get()观察到 A 的更新就不能再出现counter 1 ready false这就是这里的Ordering。1.2 Gosync/atomic1.2.1 Atomicityatomic.Int64.Add原文“Add atomically adds delta to x and returns the new value.”意思很直接Add(1)把读取、加一和写回作为一次原子更新。例如varcounter atomic.Int64// Goroutine Acounter.Add(1)// Goroutine Bcounter.Add(1)两次更新不会丢掉其中一次Goroutine A Goroutine B Add(1) Add(1) │ │ ▼ ▼ 0 → 1 1 → 2这就是Atomicity。1.2.2 VisibilityThe Go Memory Model - Atomic Values 原文“If the effect of an atomic operation A is observed by atomic operation B, then A is synchronized before B.”意思是如果 B 的 Atomic 操作观察到了 A 的 Atomic 更新那么 A 和 B 之间就建立了synchronized-before关系。继续使用ready countervarcounter atomic.Int64varreadybool// Goroutine Areadytrue// A1counter.Add(1)// A2// Goroutine Bifcounter.Load()1{// B1fmt.Println(ready)// B2}假设 B 的counter.Load()读到的1就是 A 的Add(1)产生的结果Goroutine A Goroutine B A1 ready true │ │ sequenced-before ▼ A2 counter.Add(1) │ │ synchronized-before │ Go Memory Model └──────────────────────────► B1 counter.Load() 1 │ │ sequenced-before ▼ B2 read ready因此A 在 Atomic 更新之前写入的ready true对 B 后续的读取可见。这就是Visibility。1.2.3 Ordering同一节还规定所有 Atomic 操作表现得像处在“some sequentially consistent order”Go Memory Model 又把 happens-before 定义为sequenced-before和synchronized-before的传递闭包。因此上面的关系可以直接推成A1 ready true ↓ sequenced-before A2 counter.Add(1) ↓ synchronized-before B1 counter.Load() 1 ↓ sequenced-before B2 read ready也就是A1 happens-before A2 A2 happens-before B1 B1 happens-before B2 ↓ transitivity A1 happens-before B2所以 B 已经观察到counter 1后不能仍然把 A 在此之前的ready true当作没有发生。这就是Ordering。1.3 CPython应用层没有对称的 Atomic APIPython 标准库目前没有与 JavaAtomicInteger、Goatomic.Int64对称的通用整数 Atomic API。因此Python 应用代码没有一组可以像 Java、Go 那样直接引用的 Atomic 规则。普通的counter 1不是 Python 语言层定义的 Atomic API也不能因为某个 CPython 配置存在 GIL或者 Runtime 内部使用_Py_atomic_*就把它当作应用层可以依赖的跨实现 Atomicity、Visibility 或 Ordering 保证。CPython Runtime 确实需要 Atomic 来同步自己的共享状态。它如何把_Py_atomic_*落到编译器和 CPU是下一篇的实现问题而不是 Python 应用层公开语义的一部分。2. 下一篇Atomic 是怎么实现的这一篇停在语言层Java 和 Go 分别通过公开 Atomic API 与内存模型定义 Atomicity、Visibility 和 OrderingPython 应用层则没有对称的通用 Atomic API。下一篇会把这些语言层规则转换成实现层真正需要解决的问题分别沿着 JavaAtomicInteger、Gosync/atomic和 CPython Runtime 内部的_Py_atomic_*从 Runtime 一直看到 CPU。本文首发于 ThinkerQAQ 的个人博客由作者本人同步发布。原文可能持续修订最新版本请以个人博客为准。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

小白程序员转行Agent必备:3步上手大模型,收藏这份进阶路线! 2026/9/29 11:03:05

小白程序员转行Agent必备:3步上手大模型,收藏这份进阶路线!

本文针对想转行AI Agent的程序员,指出误区在于过度强调数学和算法研发。实际转行关键在于将大模型作为中间件使用,通过API调用和工程能力即可实现。文章提供了3步实用路线:先用Python调通大模型API,再掌握LangChain等框架&#xf…

阅读更多 →
Cursor接入蓝湖MCP:让AI直接读懂设计稿,告别“还原了吗” 2026/9/29 11:03:04

Cursor接入蓝湖MCP:让AI直接读懂设计稿,告别“还原了吗”

“还原了吗?”这句话在我过去五年的开发日常里,出现频率稳居前三。每次需求进入联调阶段,设计师总会准时出现在 IM 上,发来这灵魂一问。而我这边,要么在截图里用红框圈出“这里差了 2px”,要么在十几个命名…

阅读更多 →
Win10纯净版安装U盘制作与UEFI全新部署教程 2026/9/29 11:02:57

Win10纯净版安装U盘制作与UEFI全新部署教程

装系统这件事,说简单是因为它已经标准化到几乎不需要动脑子,说麻烦是因为每一步都埋着几个只有踩过才知道的坑。我这十来年经手的机器没有一千也有八百台,从早年的光盘刻录、Ghost 还原,到现在主力用 Win10 系统安装U盘 做全新部署…

阅读更多 →
C# WPF工业上位机开发:半导体晶圆搬运与石墨岛温控实战 2026/9/29 11:02:49

C# WPF工业上位机开发:半导体晶圆搬运与石墨岛温控实战

1. 项目本质与真实场景还原:这不是一个“桌面小工具”,而是一套产线级工业控制中枢“硬核实战:C# WPF 打造半导体晶圆与石墨岛搬移上位机系统”——这个标题里每一个词都带着沉甸甸的产线分量。我干过三年封测厂EAP系统现场实施,…

阅读更多 →
公路隧道漏水识别分割数据集:27张labelme标注与训练实战 2026/9/29 11:02:17

公路隧道漏水识别分割数据集:27张labelme标注与训练实战

1. 为什么27张图的漏水数据集值得单独拿出来说公路隧道漏水识别这个方向,听起来冷门,但只要你接触过隧道巡检、地铁管养、桥隧结构健康监测这类项目,就知道它有多刚需。传统做法是人工拿着手电筒在隧道壁上找渗水痕迹,一条几公里的…

阅读更多 →
基于WinSock的TCP/UDP聊天程序实现详解:从Socket到MFC界面优化 2026/9/29 11:02:10

基于WinSock的TCP/UDP聊天程序实现详解:从Socket到MFC界面优化

简介:东南大学计算机网络第四次实验报告,围绕基于TCP/IP与UDP/IP的通信应用程序设计展开,适合自动化、计算机、信息通信等专业学生参考。报告内容覆盖实验目的与要求、实验原理、方案与步骤、设备配置、实验记录、总结及部分代码,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉