通过实例解析JMM和Volatile底层原理
这篇文章主要介绍了通过实例解析JMM和Volatile底层原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
JMM和volatile分析
1.JMM:JavaMemoryModel,java线程内存模型
2.JMM和8大原子操作结合
3.volatile的应用及底层原理探究
publicclassVolatileTest{
privatestaticvolatilebooleanflag=false;
publicstaticvoidmain(String[]args){
update();
}
publicstaticvoidupdate(){
flag=true;
System.out.println(flag);
}
}
VolatileJIT编译器编译java代码为汇编指令查看
1.在jdk\jre\bin\目录下添加hsdis-amd64.lib
2.在jdk1.8\jre\bin\server\目录下添加hsdis-amd64.dll文件
3.在IDEA中设置JVM参数
-server-Xcomp-XX:+UnlockDiagnosticVMOptions-XX:+PrintAssembly-XX:CompileCommand=compileonly,VolatileTest.update
4.运行Java程序即可打印出
CompilerOracle:compileonly*VolatileTest.update
LoadeddisassemblerfromE:\EclipseDev\jdk\jdk1.8\jre\bin\server\hsdis-amd64.dll
Decodingcompiledmethod0x000000000f11aad0:
Code:
Argument0isunknown.RIP:0xf11ac40Codesize:0x000002a8
[Disassemblingformach='amd64']
[EntryPoint]
[VerifiedEntryPoint]
[Constants]
#{method}{0x0000000008792b78}'update''()V'in'com/yew/test/VolatileTest'
#[sp+0x40](spofcaller)
0x000000000f11ac40:movdwordptr[rsp+0ffffffffffffa000h],eax
0x000000000f11ac47:pushrbp
0x000000000f11ac48:subrsp,30h
0x000000000f11ac4c:movr8,8792d70h;{metadata(methoddatafor{method}{0x0000000008792b78}'update''()V'in'com/yew/test/VolatileTest')}
0x000000000f11ac56:movedx,dwordptr[r8+0dch]
0x000000000f11ac5d:addedx,8h
0x000000000f11ac60:movdwordptr[r8+0dch],edx
0x000000000f11ac67:movr8,8792b70h;{metadata({method}{0x0000000008792b78}'update''()V'in'com/yew/test/VolatileTest')}
0x000000000f11ac71:andedx,0h
0x000000000f11ac74:cmpedx,0h
0x000000000f11ac77:je0f11ad68h;*iconst_1
;-com.yew.test.VolatileTest::update@0(line17)
0x000000000f11ac7d:movr8,0d7b08a30h;{oop(a'java/lang/Class'='com/yew/test/VolatileTest')}
0x000000000f11ac87:movedx,1h
0x000000000f11ac8c:movbyteptr[r8+68h],dl
volatile修饰
0x000000000f11ac90:lockadddwordptr[rsp],0h;*putstaticflag
;-com.yew.test.VolatileTest::update@1(line17)
无Volatile修饰
0x000000000f113707:movbyteptr[r8+68h],1h;*putstaticflag
;-com.yew.test.VolatileTest::update@1(line17)
通过比较可知:改变共享变量flag的值为true,该变量由Volatile修饰,进行汇编打印时,会有lock前缀修饰,根据IA-32架构软件开发者手册可知,lock前缀指令在多核CPU处理器下会引发两件事情:
【1】将当前处理器缓存行的数据立即写回系统内存
【2】wirte操作会使其他处理器中缓存该内存地址的数据无效
LOCK#声言期间,处理器独占任何共享内存。IA-32处理器和Intel64处理器使用MESI(修改、独占、共享、无效)控制协议去维护内部缓存和其他处理器缓存的一致性。通过嗅探技术保证处理器内部缓存、系统缓存和其他处理器缓存的数据再总线上保持一致。当其他处理器打算回写内存地址,该地址是共享内存区域,那么嗅探的处理器会将它的缓存行设置为无效,下次访问相同内存时,强制执行缓存行填充。
0x000000000f11ac95:nop
0x000000000f11ac98:jmp0f11add4h;{no_reloc}
0x000000000f11ac9d:addbyteptr[rax],al
0x000000000f11ac9f:addbyteptr[rax],al
0x000000000f11aca1:addbyteptr[rsi+0fh],ah
0x000000000f11aca4:Fatalerror:Disassemblingfailedwitherrorcode:15Decodingcompiledmethod0x000000000f11ef50:
Code:
Argument0isunknown.RIP:0xf11f080Codesize:0x00000058
[EntryPoint]
[VerifiedEntryPoint]
[Constants]
#{method}{0x0000000008792b78}'update''()V'in'com/yew/test/VolatileTest'
#[sp+0x20](spofcaller)
0x000000000f11f080:movdwordptr[rsp+0ffffffffffffa000h],eax
0x000000000f11f087:pushrbp
0x000000000f11f088:subrsp,10h
0x000000000f11f08c:movr10,0d7b08a30h;{oop(a'java/lang/Class'='com/yew/test/VolatileTest')}
0x000000000f11f096:movbyteptr[r10+68h],1h
0x000000000f11f09b:lockadddwordptr[rsp],0h;*putstaticflag
;-com.yew.test.VolatileTest::update@1(line17)
0x000000000f11f0a0:movedx,1ch
0x000000000f11f0a5:nop
0x000000000f11f0a7:call0f0557a0h;OopMap{off=44}
;*getstaticout
;-com.yew.test.VolatileTest::update@4(line18)
;{runtime_call}
0x000000000f11f0ac:int3;*getstaticout
;-com.yew.test.VolatileTest::update@4(line18)
0x000000000f11f0ad:hlt
0x000000000f11f0ae:hlt
0x000000000f11f0af:hlt
0x000000000f11f0b0:hlt
0x000000000f11f0b1:hlt
0x000000000f11f0b2:hlt
0x000000000f11f0b3:hlt
0x000000000f11f0b4:hlt
0x000000000f11f0b5:hlt
0x000000000f11f0b6:hlt
0x000000000f11f0b7:hlt
0x000000000f11f0b8:hlt
0x000000000f11f0b9:hlt
0x000000000f11f0ba:hlt
0x000000000f11f0bb:hlt
0x000000000f11f0bc:hlt
0x000000000f11f0bd:hlt
0x000000000f11f0be:hlt
0x000000000f11f0bf:hlt
[ExceptionHandler]
[StubCode]
0x000000000f11f0c0:jmp0f0883a0h;{no_reloc}
[DeoptHandlerCode]
0x000000000f11f0c5:call0f11f0cah
0x000000000f11f0ca:subqwordptr[rsp],5h
0x000000000f11f0cf:jmp0f057600h;{runtime_call}
0x000000000f11f0d4:hlt
0x000000000f11f0d5:hlt
0x000000000f11f0d6:hlt
0x000000000f11f0d7:hlt
true
4.volatile的使用优化
java并发大师DougLi在jdk7并发包中新增了一个队列集合LinkeTransferQueue,它在使用Volatile关键字修饰变量时,采用追加字节的方式将变量填充到64字节
volatile修饰变量在进行修改时,会进行LOCK前置指令加锁,锁住缓存行的数据独占
适用于:缓存行字节为64字节处理器如I7酷睿PentiumM等
不适用:非64字节宽的缓存行P6系列或者奔腾共享变量不会被频繁的写
5.并发编程的三大特性:可见性、原子性、有序性
volatile可以保证可见性、有序性,但是不保证原子性。
6.volatile关键字的语义分析
(1)保证可见性,volatile修饰的共享变量被修改时,其他处理器能立刻嗅探到共享变量值的改变
(2)保证有序性:根据happens-before原则可知,当变量使用volatile修饰时,程序代码前后的位置不能发生指令重排和提取。
(3)volatile底层采用汇编的lock前缀指令锁定共享变量内存地址的缓存行,从而控制并发的安全性(轻量级synchronized)
7.volatile使用场景以及和synchronized的区别
使用场景:1.标志状态2.DCL--双重检测锁(单例模式)3.保证可见性、顺序性
区别:
1.使用上:volatile修饰变量synchronized修饰方法或者代码块
2.原子性的保证volatile不保证原子性synchronized可以保证原子性
3.可见性保证机制不同volatile通过汇编的lock前缀指令synchronized使用Monitor属性(Moniterentet入口Moniterexit--出口(包含异常))
4.有序性保证的锁的粒度volatile粒度小,synchronized粒度大
5.其他volatile不会引起线程阻塞synchronized会引起线程的阻塞
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。