Java内存模型之volatile的底层实现机制

简介:

定义

java 语言规范对volatile 关键字的定义如下
screenshot
比较重要的一句话是:A file may be declared volatile, in which case the java
Memory Model ensures that all threads see a consistent value for the variable.
理解起来就是,对声明为 volatile 的属性,JMM能确保所有线程对这个属性看到的值是一致的(也就是说 volatile 能提供可见性)。然后我们就可以利用这个可见性大做文章,比如实现一个锁等。

HOW ——> volatile 能提供可见性

   二话不说开始撸代码吧:
AI 代码解读
public class TestOne  {
    private static volatile int a = 1;
    
    public static void test() {
            a = 2;     // 5
    }

    public static void main(String [] args) {
        test();
    }
}
AI 代码解读
 我们利用hsdis插件对上述代码进行反汇编:在控制台输入如下命令
 java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -Xcomp -XX:CompileCommand=compileonly,*TestOne.test TestOne
 参数+PrintAssembly 的意思是打印出汇编代码,对于线上版的Hotspot 想打印出汇编代码需要加上参数+UnlockDiagnosticVMOptions。-Xcomp 参数是让JVM以编译模式执行代码,而不必要等到临界“热点”才触发JIT编译。
-XX:CompileCommand=compileonly,*TestOne.test 意思是只编译test方法,没有这个参数会输出一大推对这次实验没有用的汇编代码。
 结果如下:
AI 代码解读
    Code:
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} {0x00007f1718c00258} 'test' '()V' in 'TestOne'
  #           [sp+0x40]  (sp of caller)
  0x00007f1719108de0: mov    %eax,-0x14000(%rsp)
  0x00007f1719108de7: push   %rbp
  0x00007f1719108de8: sub    $0x30,%rsp         ;*iconst_2
                                                ; - TestOne::test@0 (line 5)

  0x00007f1719108dec: movabs $0xf6404248,%rsi   ;   {oop(a 'java/lang/Class' = 'TestOne')}
  0x00007f1719108df6: mov    $0x2,%edi
  0x00007f1719108dfb: mov    %edi,0x68(%rsi)
  0x00007f1719108dfe: lock addl $0x0,(%rsp)     ;*putstatic a
                                                ; - TestOne::test@1 (line 5)

  0x00007f1719108e03: add    $0x30,%rsp
  0x00007f1719108e07: pop    %rbp
  0x00007f1719108e08: test   %eax,0x16dc12f2(%rip)        # 0x00007f172feca100
                                                ;   {poll_return}
看到 lock addl 指令没,它刚好对应 Java源码中的第五行代码。这个 lock 前缀指令,正是volatile 具有可见性的奥秘的所在。
翻一翻 intel 开发手册(卷三第八章)
AI 代码解读

screenshot
上面画红圈的表明,处理器对volatile 的实现不是对系统总线进行加锁,而是对缓存加锁。

screenshot
上面是处理器对缓存加锁的实现方式:
① 对缓存行加锁内容的修改会导致修改后的值马上回写内存
② 该处理器会阻止其他处理器缓存相同的内容(意思就是清空其他处理器中相同的值)

通过 ① ② 处理器的实现机制,java 中的volatile 就可以实现可见性了。


博客内容参考自 《Java 并发编程的艺术》第二章 volatile 的应用

小路子
+关注
目录
打赏
0
0
0
0
2
分享
相关文章
PyTorch CUDA内存管理优化:深度理解GPU资源分配与缓存机制
本文深入探讨了PyTorch中GPU内存管理的核心机制,特别是CUDA缓存分配器的作用与优化策略。文章分析了常见的“CUDA out of memory”问题及其成因,并通过实际案例(如Llama 1B模型训练)展示了内存分配模式。PyTorch的缓存分配器通过内存池化、延迟释放和碎片化优化等技术,显著提升了内存使用效率,减少了系统调用开销。此外,文章还介绍了高级优化方法,包括混合精度训练、梯度检查点技术及自定义内存分配器配置。这些策略有助于开发者在有限硬件资源下实现更高性能的深度学习模型训练与推理。
68 0
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
163 29
JVM简介—1.Java内存区域
理解的Java中SPI机制
本文深入解析了JDK提供的Java SPI(Service Provider Interface)机制,这是一种基于接口编程、策略模式与配置文件组合实现的动态加载机制,核心在于解耦。文章通过具体示例介绍了SPI的使用方法,包括定义接口、创建配置文件及加载实现类的过程,并分析了其原理与优缺点。SPI适用于框架扩展或替换场景,如JDBC驱动加载、SLF4J日志实现等,但存在加载效率低和线程安全问题。
理解的Java中SPI机制
Java 中 .length 的使用方法:深入理解 Java 数据结构中的长度获取机制
本文深入解析了 Java 中 `.length` 的使用方法及其在不同数据结构中的应用。对于数组,通过 `.length` 属性获取元素数量;字符串则使用 `.length()` 方法计算字符数;集合类如 `ArrayList` 采用 `.size()` 方法统计元素个数。此外,基本数据类型和包装类不支持长度属性。掌握这些区别,有助于开发者避免常见错误,提升代码质量。
33 1
【Java并发】【volatile】适合初学者体质的volatile
当你阅读dalao的框架源码的时候,你是否会见到这样一个关键字 - - - volatie,诶,你是否会好奇,为什么要加它?加了它有什么作用?
80 14
【Java并发】【volatile】适合初学者体质的volatile
|
1月前
|
【原理】【Java并发】【volatile】适合初学者体质的volatile原理
欢迎来到我的技术博客!我是一名热爱编程的开发者,梦想是写出高端的CRUD应用。2025年,我正在沉淀自己,博客更新速度也在加快。在这里,我会分享关于Java并发编程的深入理解,尤其是volatile关键字的底层原理。 本文将带你深入了解Java内存模型(JMM),解释volatile如何通过内存屏障和缓存一致性协议确保可见性和有序性,同时探讨其局限性及优化方案。欢迎订阅专栏《在2B工作中寻求并发是否搞错了什么》,一起探索并发编程的奥秘! 关注我,点赞、收藏、评论,跟上更新节奏,让我们共同进步!
144 8
【原理】【Java并发】【volatile】适合初学者体质的volatile原理
【YashanDB知识库】kettle同步大表提示java内存溢出
在数据导入导出场景中,使用Kettle进行大表数据同步时出现“ERROR:could not create the java virtual machine!”问题,原因为Java内存溢出。解决方法包括:1) 编辑Spoon.bat增大JVM堆内存至2GB;2) 优化Kettle转换流程,如调整批量大小、精简步骤;3) 合理设置并行线程数(PARALLELISM参数)。此问题影响所有版本,需根据实际需求调整相关参数以避免内存不足。
|
2月前
|
Volatile关键字与Java原子性的迷宫之旅
通过合理使用 `volatile`和原子操作,可以在提升程序性能的同时,确保程序的正确性和线程安全性。希望本文能帮助您更好地理解和应用这些并发编程中的关键概念。
55 21
|
1月前
|
Java静态代码块深度剖析:机制、特性与最佳实践
在Java中,静态代码块(或称静态初始化块)是指类中定义的一个或多个`static { ... }`结构。其主要功能在于初始化类级别的数据,例如静态变量的初始化或执行仅需运行一次的初始化逻辑。
64 4
|
2月前
|
java设置栈内存大小
在Java应用中合理设置栈内存大小是确保程序稳定性和性能的重要措施。通过JVM参数 `-Xss`,可以灵活调整栈内存大小,以适应不同的应用场景。本文介绍了设置栈内存大小的方法、应用场景和注意事项,希望能帮助开发者更好地管理Java应用的内存资源。
83 4

热门文章

最新文章