JVM系列之:从汇编角度分析Volatile
发布时间:2023-11-26 14:33:46
Volatile关键字对熟悉java多线程的朋友来说,应该很熟悉了。Volatile是JMM(Java Memory Model)的一个非常重要的关键词。通过是用Volatile可以实现禁止重排序和变量值线程之间可见两个主要特性。今天我们从汇编的角度来分析一下Volatile关键字到底是怎么工作的。
重排序
这个世界上有两种重排序的方式。
第一种,是在编译器级别的,你写一个java源代码,经过javac编译之后,生成的字节码顺序可能跟源代码的顺序不一致。
第二种,是硬件或者CPU级别的重排序,为了充分利用多核CPU的性能,或者CPU自身的处理架构(比如cache line),可能会对代码进行重排序。比如同时加载两个非互相依赖的字段进行处理,从而提升处理速度。
我们举个例子:
public class TestVolatile { private static int int1; private static int int2; private static int int3; private static int int4; private static int int5; public static void mAIn(String[] args) throws InterruptedException { for (int i = ; i < 10000; i++) { increase(i); } Thread.sleep(1000); } private static void increase(int i){ int1= i+1; int2= i+2; int3= i+3; int4= i+4; int5= i+5; }}
上面例子中,我们定义了5个int字段,然后在循环中对这些字段进行累加。
先看下javac编译出来的字节码的顺序:

我们可以看到在设置值的过程中是和java源代码的顺序是一致的,是按照int1,int2,int3,int4,int5的顺序一个一个设置的。
然后我们看一下生成的汇编语言代码:
在运行时添加参数-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:-Inline,或者直接使用JIT Watcher。
从生成的代码中,我们可以看到putstatic是按照int1,int5,int4,int3,int2的顺序进行的,也就是说进行了重排序。
如果我们将int2设置成为Volatile,看看结果如何?
前方高能预警,请小伙伴们做好准备
我们先看putstatic的顺序,从注释里面,我们只发现了putstatic int2, int3和int5。
要是没有能独立思考和独立决定的有创造个人,社会的向上发展就不可想像 – 爱因斯坦
这里是反编译的时候注释写错了!
让我们来仔细分析一下汇编代码。
第一个红框,不用懂汇编语言的朋友应该也可以看懂,就是分别给r11d,r8d,r9d,ecx和esi这5个寄存器分别加1,2,3,4,5。
这也分别对应了我们在increase方法中要做的事情。
有了这些寄存器的值,我们再继续往下看,从而可以知道,第二个红框实际上表示的就是putstatic int1,而最后一个红框,表示的就是putstatic int4。
所以,大家一定要学会自己分析代码。
5个putstatic都在,同时因为使用了volatile关键字,所以int2作为一个分界点,不会被重排序。所以int1一定在int2之前,而int3,4,5一定在int2之后。
上图的结果是在JIT Watcher中的C2编译器的结果,如果我们切换到C1编译器:
这次结果没错,5个int都在,同时我们看到这5个int居然没有重排序。
这也说明了不同的编译器可能对重排序的理解程度是不一样的。
写的内存屏障再来分析一下上面的putstatic int2:
lock addl $0x,-0x40(%rsp) ;*putstatic int2 {reexecute= rethrow= return_oop=}
这里使用了 lock addl指令,给rsp加了0。rsp是SP (Stack Pointer) register,也就是栈指针寄存器。
给rsp加0,是不是很奇怪?
加0,虽然没有改变rsp的值,但是因为前面加了lock,所以这个指令会被解析为内存屏障。
这个内存屏障保证了两个事情,第一,不会重排序。第二,所有的变量值都会回写到主内存中,从而在这个指令之后,变量值对其他线程可见。
当然,因为使用lock,可能对性能会有影响。
非lock和LazySet
上面我们提到了volatile会导致生成lock指令。
但有时候,我们只是想阻止重排序,对于变量的可见性并没有那么严格的要求。
这个时候,我们就可以使用Atomic类中的LazySet:
public class TestVolatile2 { private static int int1; private static AtomicInteger int2=new AtomicInteger(); private static int int3; private static int int4; private static int int5; public static void mAIn(String[] args) throws InterruptedException { for (int i = ; i < 10000; i++) { increase(i); } Thread.sleep(1000); } private static void increase(int i){ int1= i+1; int2.lazySet(i+2); int3= i+3; int4= i+4; int5= i+5; }}

从结果可以看到,int2没有重排序,也没有添加lock。
注意,上面的最后一个红框表示的是putstatic int4。
读的性能
最后,我们看下使用volatile关键字对读的性能影响:
public class TestVolatile3 { private static volatile int int1=10; public static void mAIn(String[] args) throws InterruptedException { for (int i = ; i < 10000; i++) { readInt(i); } Thread.sleep(1000); } private static void readInt(int i){ if(int1 < 5){ System.out.println(i); } }}
上面的例子中,我们对int1读取10000次。看下编译结果:

从结果可以看出,getstatic int1和不使用volatile关键字,生成的代码是一样的。
所以volatile对读的性能不会产生影响。
总 结
本文从汇编语言的角度再次深入探讨了volatile关键字和JMM模型的影响,希望大家能够喜欢。


猜你喜欢
- 要注意8个点,检查一下是否做到。一:必须是完整版OFFICE,不能是绿色版、精简版,它们不支持COM加载宏.二:必须关闭Excel状态下安装
- 近日,据外媒报道,微软正在为企业客户提供一个新的选项来下载更小的Windows 10更新包以进行分发,这可以显著节省宽带。具体来说,因为包含
- Hyer-V是一个微软的虚拟机,部署在win 8.x 64位 pro以上版本中,和Windows 2008以上服务器的版本中。是微软第一个采
- 在日常工作中,有时候我们需要打印一些信封用于邮寄信件。一般人会选择到商店购买,但是买回来的信封不一定能符合我们的使用要求。其实,使用Word
- Win8系统具备很多强大的功能和人性化的设置。其中的系统计划任务就是其中之一,所谓的任务计划就是将任何脚本、程序或文档安排在某个时间运行,比
- AI如何新建色调?最近有很多小伙伴向我询问如果ai中想要创建一个色调,应该怎么将新的颜色添加到色板中呢?今天我们就一起来看看ai添加色板的具
- 用户在wps软件中可以收获到很多实用的功能来帮助自己,自己也解决了很多文件的编辑工作,在这些功能的加持下用户可以在很大程度上提升自己编辑文件
- 大家知道,网络上的信息非常庞杂,良莠不齐,真假难辨,那怎样找到客观公正正确的消息。一、百度百科、搜狗百科、 * 图1二、政府和事业单位的网
- win7在原有的基本上有了重大的改变,界面不但变得更炫,在应用方面也给我们带来了相当多的便捷。而且win7还有一大亮点那就是库功能,一般在平
- Win10快速访问如何设置?Win10系统内置有快速访问功能,可以快速打开设置好的文件,这样我们在使用电脑的时候就很方便。有但是还是有很多用
- win10出来以后,很多用户都已经更新了,在刚开始使用新系统的时候难免会有很多功能都不知道,比如说很多用户不知道如何设置win10系统中任务
- 最近有Win7系统用户反映,Win7的界面窗口边框变得很难看而且和Win2000、WinXP的界面窗口边框很像。这是什么原因导致的呢?又该怎
- 如果想在Excel中输入连续字母,用普通的办法只能一个一个输入了,有些人会想到,第一单元格输入A,下面单元格输入B,然后选中A,B单元格,然
- 工作报表不能分享大家看,让可以让大家瞧瞧我这简单的代码,O(∩_∩)O哈哈~。具体如下:Sub 清空销量2() ‘清空后6月导入的数据res
- 近年来,用户的隐私保护意识不断增强,加密通讯市场也变得逐渐热闹起来。从 iOS 系统上的 iMessage 到 WhatsApp、再到来自俄
- word文档编辑中,有时候需要插入分页符,但是发现插入之后,文档分页了,却没有出现分页符,那么下面就由小编给大家分享下word显示分页符的技
- Win8系统使用过程中感受更多的是对频频出现的问题的抱怨,比如用久了磁盘空间越来越少该怎么解决,关于这个问题,下面以图文的形式为大家讲解下具
- 如何使用ps制作抖音图标类型的故障效果照片?给大家介绍如何使用ps制作抖音图标类型的故障效果照片,一起来看看吧。1.打开照片后,点击ctrl
- 最近,windows10系统用户反映在使用电脑观看视频的时候,发现电脑一点声音都没有,而在调节音量后发现win10任务栏的音量图标也不见了,
- 1.插入可选连字符在Word2010文档中的英文单词中间插入可选连字符的步骤如下所述:第1步,打开Word2010文档窗口,将插入点光标定位