volatile是如何禁止指令进行重排序的

简介: volatile是如何禁止指令进行重排序的

Further Reading : 内存屏障类型介绍(StoreStore,StoreLoad,LoadLoad,LoadStore)
Further Reading : 什么是指令重排

重排序分为编译器重排序和处理器重排序。 为了实现volatile内存语义,JMM会分别限制这两种类型的重排序类型。

● volatile禁止的重排序
1、当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序。这个规则确保volatile写之前的操作不会被编译器重排序到volatile写之后。
2、当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。这个规则确保volatile读之后的操作不会被编译器重排序到volatile读之前。
3、当第一个操作是volatile写,第二个操作是volatile读时,不能重排序。

●JMM针对编译器制定的volatile重排序规则表
在这里插入图片描述

● volatile如何禁止重排序的?
编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。
第1步:在每个volatile写操作的前面插入一个StoreStore屏障,后面插入一个StoreLoad屏障。
在这里插入图片描述

●StoreStore屏障 禁止上面普通写与下面volatile写重排序,上面普通读与下面volatile写如何禁止重排序?
虽然StoreStore屏障主要作用于防止store-store重排序,但在volatile写操作中实际会使用更复杂的内存屏障组合,以确保volatile写之前的普通读不会被重排到volatile写之后。

第2步:在每个volatile写操作的后面插入一个StoreLoad屏障
StoreLoad屏障 禁止 volatile写和volatile读重排序

因为编译器常常无法准确判断在一个volatile写的后面是否需要插入一个StoreLoad屏障(比如,一个volatile写之后方法立即return)。为了保证能正确实现volatile的内存语义,JMM在采取了保守策略:在每个volatile写的后面,或者在每个volatile读的前面插入一个StoreLoad屏障。从整体执行效率的角度考虑,JMM最终选择了在每个volatile写的后面插入一个StoreLoad屏障。因为volatile写-读内存语义的常见使用模式是:一个写线程写volatile变量,多个读线程读同一个volatile变量。当读线程的数量大大超过写线程时,选择在volatile写之后插入StoreLoad屏障将带来可观的执行效率的提升。从这里可以看到JMM在实现上的一个特点:首先确保正确性,然后再去追求执行效率。

第3步:在每个volatile读操作的后面插入一个LoadLoad屏障,一个LoadStore屏障。

在这里插入图片描述

LoadLoad屏障+LoadStore屏障 禁止 普通读,普通写 和volatile读重排序

相关文章
|
算法 Java 编译器
【JIT技术】
【JIT技术】
645 0
|
12月前
|
消息中间件 存储 缓存
超全面Java中的队列(Queue)
Java中的`Queue`接口位于`java.util`包,继承自`Collection`,用于存储待处理的元素,通常遵循FIFO原则。它包含`add`、`offer`、`poll`等方法,支持多种实现类,如`LinkedList`、`PriorityQueue`、`ArrayDeque`、`ConcurrentLinkedQueue`及`BlockingQueue`系列。
1100 0
|
9月前
|
canal 关系型数据库 MySQL
数据同步神器-Canal
Canal是阿里巴巴开源的MySQL增量日志解析工具,通过模拟MySQL主从复制机制,实时捕获数据库变更,实现数据同步至Kafka、Elasticsearch等系统,广泛应用于数据同步、监控、备份与迁移场景。
6726 5
|
前端开发 JavaScript Shell
鸿蒙5开发宝藏案例分享---Web页面内点击响应时延分析
本文为鸿蒙开发者整理了Web性能优化的实战案例解析,结合官方文档深度扩展。内容涵盖点击响应时延核心指标(≤100ms)、性能分析工具链(如DevTools时间线、ArkUI Trace抓取)以及高频优化场景,包括递归函数优化、网络请求阻塞解决方案和setTimeout滥用问题等。同时提供进阶技巧,如首帧加速、透明动画陷阱规避及Web组件初始化加速,并通过优化前后Trace对比展示成果。最后总结了快速定位问题的方法与开发建议,助力开发者提升Web应用性能。
dynamic-datasource动态添加移除数据源
dynamic-datasource动态添加移除数据源
1465 0
|
SQL Java 关系型数据库
SpringBoot 系列之 MyBatis输出SQL日志
这篇文章介绍了如何在SpringBoot项目中通过MyBatis配置输出SQL日志,具体方法是在`application.yml`或`application.properties`中设置MyBatis的日志实现为`org.apache.ibatis.logging.stdout.StdOutImpl`来直接在控制台打印SQL日志。
SpringBoot 系列之 MyBatis输出SQL日志
|
开发框架 Java 开发者
Spring Boot中的自动装配原理
Spring Boot中的自动装配原理
3893 1
|
存储 Java C++
JVM内存模型和结构详解(五大模型图解)
JVM内存模型和结构详解(五大模型图解)
|
缓存 Java 开发者
一文详解Spring Bean循环依赖
本文主要梳理了Spring解决bean循环依赖的思路。
44179 31