重排序
1|0重排序的定义
重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。
重排序分3种类型
- 编译器优化的重排序。编译器再不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
- 指令级并行的重排序:现代处理器基本采用指令级并行技术,来将多条指令重叠执行。如果不存在数据依赖、处理器可以改变对应的机器指令的执行顺序
- 内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
Java从源代码到最终实际执行的指令序列,会经历一下重排序
其中1操作属于编译器重排序、2和3属于处理器重排序。这些重排序可能会导致多线程程序出来内存可见性问题。对于编译器JMM的编译器重排序规则会紧张特定类型的编译器重排序、对于处理器重排序,JMM的处理器重排序规则会要 求Java编译器在生成指令序列时,插入特定类型的内存屏障(Memory Barriers,Intel称之为 Memory Fence)指令,通过内存屏障指令来禁止特定类型的处理器重排序。
JMM属于语言级的内存模型,它确保在不同的编译器和不同的处理器平台之上,通过禁止特定类型的编译器重排序和处理器重排序,为程序员提供一致的内存可见性保证。
比如volatile 修饰符,通过添加内存屏障操作,(LoadLoad、StoreStore、LoadStore、StoreLoad)禁止指令重排序,保证内存可见性。
1|1数据依赖性
如果两个操作访问一个数据变量,且存在写操作,测试两个操作就对数据产生了数据依赖性,分为一下三类
名称 | 代码实例 | 说明 |
---|---|---|
写后读 | a=1; b=a; | 写一个变量之后,再读这个位置 |
写后写 | a=1; a=2; | 写一个变量之后,再写这个变量 |
读后写 | a=b; b=1; | 读一个变量之后,再写这个变量 |
以上操作,出现重排序两个操作的执行顺序,程序结果就会发送改变,所以这样的情况下不能进行重排序。
此处说明的数据依赖只针对单个处理器中执行的指令序列的单个线程中执行的操作, 不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。
1|2as-if-serial语义
as-if-serial语义的意思是:不管怎么重排序。单线程程序的执行结果不能被改变。编译器、返回语句和处理器必须遵守。
为了遵守语义,编译器和处理器都不会对存在数据依赖的操作进行重排序,
__EOF__
本文作者:Spoon | Blog
本文链接:https://www.cnblogs.com/Spoonblog/p/16061171.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/Spoonblog/p/16061171.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)