JMM和Volatile底层原理分析

JMM和volatile分析

1.JMM:Java Memory Model,java线程内存模型

JMM:它是一个抽象的概念,描述的是线程和内存间的通信,java线程内存模型和CPU缓存模型类似,它是标准化的,用于屏蔽硬件和操作系统对内存访问的差异性

2.JMM和8大原子操作结合

3.volatile的应用及底层原理探究

volatile : 轻量级的synchronized,在多处理器的开发中保证了共享变量的"可见性"。可见性的意思:当一个线程修改了某个共享变量时,其他使用到该共享变量的线程能够及时读取到修改的值。修饰得当,比synchronized的执行成本更低,因为它不会引起线程上下文切换和调度。

public class VolatileTest {
    private static volatile boolean  flag = false;
    public static void main(String[] args) {
        update();
    }

    public static void update(){
        flag = true;
        System.out.println(flag);
    }
}
Volatile JIT编译器编译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
Loaded disassembler from E:\EclipseDev\jdk\jdk1.8\jre\bin\server\hsdis-amd64.dll
Decoding compiled method 0x000000000f11aad0:
Code:
Argument 0 is unknown.RIP: 0xf11ac40 Code size: 0x000002a8
[Disassembling for mach=‘amd64‘]
[Entry Point]
[Verified Entry Point]
[Constants]
# {method} {0x0000000008792b78} ‘update‘ ‘()V‘ in ‘com/yew/test/VolatileTest‘
# [sp+0x40] (sp of caller)
0x000000000f11ac40: mov dword ptr [rsp+0ffffffffffffa000h],eax
0x000000000f11ac47: push rbp
0x000000000f11ac48: sub rsp,30h
0x000000000f11ac4c: mov r8,8792d70h ; {metadata(method data for {method} {0x0000000008792b78} ‘update‘ ‘()V‘ in ‘com/yew/test/VolatileTest‘)}
0x000000000f11ac56: mov edx,dword ptr [r8+0dch]
0x000000000f11ac5d: add edx,8h
0x000000000f11ac60: mov dword ptr [r8+0dch],edx
0x000000000f11ac67: mov r8,8792b70h ; {metadata({method} {0x0000000008792b78} ‘update‘ ‘()V‘ in ‘com/yew/test/VolatileTest‘)}
0x000000000f11ac71: and edx,0h
0x000000000f11ac74: cmp edx,0h
0x000000000f11ac77: je 0f11ad68h ;*iconst_1
; - com.yew.test.VolatileTest::[email protected] (line 17)

0x000000000f11ac7d: mov r8,0d7b08a30h ; {oop(a ‘java/lang/Class‘ = ‘com/yew/test/VolatileTest‘)}
0x000000000f11ac87: mov edx,1h
0x000000000f11ac8c: mov byte ptr [r8+68h],dl

volatile修饰
0x000000000f11ac90: lock add dword ptr [rsp],0h ;*putstatic flag
; - com.yew.test.VolatileTest::[email protected] (line 17)

无Volatile修饰

0x000000000f113707: mov byte ptr [r8+68h],1h ;*putstatic flag
; - com.yew.test.VolatileTest::[email protected] (line 17)

通过比较可知:改变共享变量flag的值为true,该变量由Volatile修饰,进行汇编打印时,会有lock前缀修饰,根据IA-32架构软件开发者手册可知,lock前缀指令在多核CPU处理器下会引发两件事情:

【1】将当前处理器缓存行的数据立即写回系统内存

【2】wirte操作会使其他处理器中缓存该内存地址的数据无效

LOCK#声言期间,处理器独占任何共享内存。IA-32处理器和Intel 64处理器使用MESI(修改、独占、共享、无效)控制协议去维护内部缓存和其他处理器缓存的一致性。通过嗅探技术保证处理器内部缓存、系统缓存和其他处理器缓存的数据再总线上保持一致。当其他处理器打算回写内存地址,该地址是共享内存区域,那么嗅探的处理器会将它的缓存行设置为无效,下次访问相同内存时,强制执行缓存行填充。

0x000000000f11ac95: nop
0x000000000f11ac98: jmp 0f11add4h ; {no_reloc}
0x000000000f11ac9d: add byte ptr [rax],al
0x000000000f11ac9f: add byte ptr [rax],al
0x000000000f11aca1: add byte ptr [rsi+0fh],ah
0x000000000f11aca4: Fatal error: Disassembling failed with error code: 15Decoding compiled method 0x000000000f11ef50:
Code:
Argument 0 is unknown.RIP: 0xf11f080 Code size: 0x00000058
[Entry Point]
[Verified Entry Point]
[Constants]
# {method} {0x0000000008792b78} ‘update‘ ‘()V‘ in ‘com/yew/test/VolatileTest‘
# [sp+0x20] (sp of caller)
0x000000000f11f080: mov dword ptr [rsp+0ffffffffffffa000h],eax
0x000000000f11f087: push rbp
0x000000000f11f088: sub rsp,10h
0x000000000f11f08c: mov r10,0d7b08a30h ; {oop(a ‘java/lang/Class‘ = ‘com/yew/test/VolatileTest‘)}
0x000000000f11f096: mov byte ptr [r10+68h],1h
0x000000000f11f09b: lock add dword ptr [rsp],0h ;*putstatic flag
; - com.yew.test.VolatileTest::[email protected] (line 17)

0x000000000f11f0a0: mov edx,1ch
0x000000000f11f0a5: nop
0x000000000f11f0a7: call 0f0557a0h ; OopMap{off=44}
;*getstatic out
; - com.yew.test.VolatileTest::[email protected] (line 18)
; {runtime_call}
0x000000000f11f0ac: int3 ;*getstatic out
; - com.yew.test.VolatileTest::[email protected] (line 18)

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
[Exception Handler]
[Stub Code]
0x000000000f11f0c0: jmp 0f0883a0h ; {no_reloc}
[Deopt Handler Code]
0x000000000f11f0c5: call 0f11f0cah
0x000000000f11f0ca: sub qword ptr [rsp],5h
0x000000000f11f0cf: jmp 0f057600h ; {runtime_call}
0x000000000f11f0d4: hlt
0x000000000f11f0d5: hlt
0x000000000f11f0d6: hlt
0x000000000f11f0d7: hlt
true

4.volatile的使用优化

java并发大师Doug Li在jdk7并发包中新增了一个队列集合LinkeTransferQueue,它在使用Volatile关键字修饰变量时,采用追加字节的方式将变量填充到64字节

volatile修饰变量在进行修改时,会进行LOCK前置指令加锁,锁住缓存行的数据独占

适用于:缓存行字节为64字节 处理器如 I7 酷睿 Pentium M等

不适用:非64字节宽的缓存行 P6系列或者奔腾   共享变量不会被频繁的写

4.并发编程的三大特性:可见性、原子性、有序性

volatile可以保证可见性、有序性,但是不保证原子性。

原文地址:https://www.cnblogs.com/vincentYw/p/12040336.html

时间: 2024-10-11 22:21:36

JMM和Volatile底层原理分析的相关文章

HashMap底层原理分析(put、get方法)

1.HashMap底层原理分析(put.get方法) HashMap底层是通过数组加链表的结构来实现的.HashMap通过计算key的hashCode来计算hash值,只要hashCode一样,那hash值就是相同的.当hash值相同时,就会出现hash冲突,HashMap通过链表来解决冲突. 原理图: 实例: import java.util.HashMap; import java.util.Map; ? public class HashMapTest { public static vo

AQS底层原理分析

J.U.C 简介 Java.util.concurrent 是在并发编程中比较常用的工具类,里面包含很多用来在并发场景中使用的组件.比如线程池.阻塞队列.计时器.同步器.并发集合等等.并发包的作者是大名鼎鼎的 Doug Lea.我们在接下来剖析一些经典的比较常用的组件的设计思想. Lock Lock 在 J.U.C 中是最核心的组件,前面我们讲 synchronized 的时候说过,锁最重要的特性就是解决并发安全问题.为什么要以 Lock 作为切入点呢?如果有看过 J.U.C 包中的所有组件,一

class底层原理分析

class 类名 会把类构造出来 实际上是:元类实例化产生类 这个对象 类实例化产生对象,一定是: 类名() Person 类是由type实例化产生,传一堆参数 type() 调用类的__init__方法 type() type(object_or_name,bases,dict) object_or_name 类的名字,是个字符串 bases:是它的所有的父类,基类 dict :名称空间,是一个字典 通过type来直接产生类,不用class关键字了 l={} exec(''' school =

volatile底层实现原理

前言 当共享变量被声明为volatile后,对这个变量的读/写操作都会很特别,下面我们就揭开volatile的神秘面纱. 1.volatile的内存语义 1.1 volatile的特性 一个volatile变量自身具有以下三个特性: 可见性:即当一个线程修改了声明为volatile变量的值,新值对于其他要读该变量的线程来说是立即可见的.而普通变量是不能做到这一点的,普通变量的值在线程间传递需要通过主内存来完成. 有序性:volatile变量的所谓有序性也就是被声明为volatile的变量的临界区

Java中CAS底层实现原理分析

CAS(无锁优化.自旋锁)原理分析 一.CAS(compareAndSwap)的概念 CAS,全称Compare And Swap(比较与交换),解决多线程并行情况下使用锁造成性能损耗的一种机制. CAS(V, A, B),V为内存地址.A为预期原值,B为新值.如果内存地址的值与预期原值相匹配,那么将该位置值更新为新值.否则,说明已经被其他线程更新,处理器不做任何操作:无论哪种情况,它都会在 CAS 指令之前返回该位置的值.而我们可以使用自旋锁,循环CAS,重新读取该变量再尝试再次修改该变量,也

深入源码分析SpringMVC底层原理(二)

原文链接:深入源码分析SpringMVC底层原理(二) 文章目录 深入分析SpringMVC请求处理过程 1. DispatcherServlet处理请求 1.1 寻找Handler 1.2 没有找到Handler的处理 1.3 根据Handler寻找Adapter 1.4 拦截器的处理 1.5 Adapter处理请求 1.6 异常视图的处理 1.7 页面的跳转 2.总结 在上一篇文章中我们讲到了SpringMVC的初始化,分别初始化两个ApplicationContext,并且初始化一些处理器

(一)Python入门-3序列:17字典-核心底层原理-内存分析-存储键值对过程

字典核心底层原理(重要) 字典对象的核心是散列表.散列表是一个稀疏数组(总是有空白元素的数组),数组的 每个单元叫做 bucket.每个 bucket 有两部分:一个是键对象的引用,一个是值对象的引 用. 由于,所有bucket 结构和大小一致,我们可以通过偏移量来读取指定 bucket. 一:将一个键值对放进字典的底层过程 >>> a = {} >>> a["name"]="jack" 假设字典 a对象创建完后,数组长度为 8:

全面理解Java内存模型(JMM)及volatile关键字(转)

原文地址:全面理解Java内存模型(JMM)及volatile关键字 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoader) 深入理解Java并发之synchronized实现原理 Java并发编程-无锁CAS与Unsafe类及其并发包Atomic 深入理解Java内存模型(JMM)及volatile关键字 剖析基于并发AQS的重入锁(Reetr

java并发包&线程池原理分析&锁的深度化

      java并发包&线程池原理分析&锁的深度化 并发包 同步容器类 Vector与ArrayList区别 1.ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中.当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制.移动.代价比较高.因此,它适合随机查找和遍历,不适合插入和删除. 2.Vector与Arra