`

JAVA虚拟机-JMM内存模型(六)

 
阅读更多

1.JMM (Java Memory Model)内存模型相关概念

模型图:

可以对应下面这张图:

 

 

 

这张图告诉我们在线程运行的时候有一个内存专用的一小块内存,当Java程序会将变量同步到线程所在的内存,这时候会操作工作内存中的变量,而线程 中变量的值何时同步回主内存是不可预期的。但同时Java内存模型又告诉我们通过使用关键词“synchronized”或“volatile”可以让 Java保证某些约束:

“volatile” — 保证读写的都是主内存的变量
“synchronized” — 保证在块开始时都同步主内存的值到工作内存,而块结束时将变量同步回主内存.

 本地内存是什么,数据存在哪里?
     1、java内存模型的抽象概念
     2、并不在堆中,而是在cpu中的物理cache

可参考:http://www.cnblogs.com/dolphin0520/p/3920373.html 第一部分

Intel 的MESI协议,MESI协议保证了每个缓存中使用的共享变量的副本是一致的。它核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。

 

 跨核访问需要通过Memory Controller
问题:为什么需要这样?
     访问快!!
     就像:访问mysql时,常用结果会被缓存到redis等缓存产品一样;
     Cpu与内存的交互速度远慢于cpu的运算速度为了提高处理速度,先进系统内存的数据读到内存缓存(L1,L2,L3等)
缓存行(Cache line)
 为了高效地存取缓存, 不是简单随意地将单条数据写入缓存的.  缓存是由缓存行组成的, 典型的一行是64字节.

读者可以通过下面的shell命令,查看cherency_line_size就知道知道机器的缓存行是多大。
  cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size  

 查看下面这台机器: 16个cpu 每个为4核  缓存行64字节

 

 2.并发编程几个重要概念

2.1 三个特性

在并发编程中,我们通常会遇到以下三个问题:原子性问题,可见性问题,有序性问题。我们先看具体看一下这三个概念:

1).原子性

     原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

2).可见性

  可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

3).有序性

  有序性:即程序执行的顺序按照代码的先后顺序执行。

 

2.2 重排序

JMM属于语言级的内存模型,它确保在不同的编译器不同的处理器平台之上,通过禁止特定类型的编译器重排序和处理器重排序,为程序员提供一致的内存可见性保证
对于编译器冲排序,JMM的编译器重排序规则会禁止特定类型的编译器重排序(不是所有的编译器重排序都要禁止)。
对于处理器重排序,JMM的处理器重排序规则会要求java编译器在生成指令序列时,插入特定类型的内存屏障(memory barriers,intel称之为memory fence)指令,通过内存屏障指令来禁止特定类型的处理器重排序(不是所有的处理器重排序都要禁止)。

引申:

在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序。重排序分三种类型:

  1. 编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
  2. 指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
  3. 内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。

上述的1属于编译器重排序,2和3属于处理器重排序。这些重排序都可能会导致多线程程序出现内存可见性问题
 2.3 内存屏障memory Barriers
内存屏障类型
   
volatile语义中内存屏障的插入策略
     在每个volatile写前面插入SS
     在每个volatile写后面插入SL
     在每个volatile读后面插入LL,插入LS
连续的操作之间多余的内存屏障会由编译器觉得是否省略。
     同时,不同的操作系统所允许的重排序类型也不尽相同,例如x86只允许sl重排序,所以其实只需要加这一种内存屏障即可。
 

3.volatile,final,synchronized锁语义

3.1 volatile内存语义   

      允许线程访问共享变量。为了确保共享变量能够被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。
          1、某些情况比锁更加方便
          2、内存模型确保线程可以看到的变量的值是一致的
     Lock前缀的指令
          java -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*类名.方法名 类名
         
          1、将当前处理器缓存行的数据写回系统内存
          2、使其他CPU里缓存了该内存地址的数据无效
          缓存一致性协议:每个处理器嗅探总线上传播的数据来检查自己缓存的值是否过期,当发现缓存行对应的内存地址被修改,会将当前行设置成无效状态,再次操作,会重新从系统内存中读取
          可见性:对一个volatile变量的读,总能看到(任意线程)对这个变量最后的写入。
          原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性,obj = new Object();也不是原子性

 

3.2 final域的内存语义
     final域,编译器和处理器遵守两个重排序规则
     1、在构造器内对final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。SS屏障
     2、初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。LL屏障
     防止域从构造器中溢出。旧的内存模型中,可能看到final域的值为0,稍后由于初始化,发现final域的值变为1,这是比较尴尬的,所有JSR-133增强了final的语义,只要对象正确构造(被构造对象的引用在构造器中没有溢出),那么不需要使用同步,就可以保证任意线程都能看到final域在构造器中被初始化之后的值。
     同时x86处理器只允许SL重排序,所以final语义的实现其实无需增加内存屏障。

 

3.3 锁的内存语义

 

 

 待续......

 

 

 

1.解决以下问题:

1).JMM内存模型中本地缓存和工作内存是什么关系?

2).重排序在什么时候进行?(JIT编译优化时进行)

3).什么是内存屏障Memory Barriers,内存屏障帮我做了什么?4).内存屏障的4种插入形式?

5).原子性 可见性 重排序 顺序一致性的解释?

6).volatile,synchronized,final的语义

7).as-id-serial,happens-before的语义

 

相关文章:

 

参考:

1.聊聊我对Java内存模型的理解

       2.Java并发编程:volatile关键字解析

      3.并发编程网: JAVA内存模型

 

 

  • 大小: 12.1 KB
  • 大小: 49.4 KB
  • 大小: 29.7 KB
  • 大小: 22.7 KB
  • 大小: 13.4 KB
  • 大小: 2.9 KB
  • 大小: 35.3 KB
  • 大小: 9.6 KB
  • 大小: 7.3 KB
  • 大小: 21 KB
分享到:
评论

相关推荐

    浅析java内存模型--JMM(JavaMemoryModel)

    在说Java内存模型之前,我们先说一下Java的内存结构,也就是运行时的数据区域:Java虚拟机在执行Java程序的过程中,会把它管理的内存划分为几个不同的数据区域,这些区域都有各自的用途、创建时间、销毁时间

    JSR-133-JMM.zip

    本文是JSR-133规范,即JavaTM内存模型与线程规范,由JSR-133专家组开发。本规范是JSR-176(定义了JavaTM平台 Tiger(5.0)发布版的主要特性)的一部分。本规范的标准内容将合并到JavaTM语言规范、JavaTM虚拟机规范...

    Java内存模型JMM浅析

    Java Memory Model简称JMM, 是一系列的Java虚拟机平台对开发者提供的多线程环境下的内存可见性、是否可以重排序等问题的无关具体平台的统一的保证。(可能在术语上与Java运行时内存分布有歧义,后者指堆、方法区、...

    JAVA内存模型

    Java被设计为跨平台的语言,在内存管理上,显然也要有一个统一的模型。而且Java语言最大的特点就是废除了指针,把程序员从痛苦中解脱出来,不用再考虑内存使用和管理方面的问题。 可惜世事总不尽如人意,虽然JMM设计...

    jvm详细内存模型图1

    查看《深入理解Java虚拟机》后,自己简单总结的jvm相关的简单模型图。

    JMM&JSR;.rar

    Java程序是需要运行在Java虚拟机上面的,Java内存模型(Java Memory Model ,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能保证效果一致的...

    Java内存模型与volatile关键字

     Java内存模型(JMM),不同于Java运行时数据区,JMM的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中读取数据这样的底层细节。JMM规定了所有的变量都存储在主内存中,但每个...

    Java高并发实战_java高并发_高并发_

    介绍了两个重要的并行性能评估定律, 以及 Java 内存模型 JMM。第2章介绍了 Java 并行程序开发的基础, 包括 Java 中 Thread 的基本使用方法等第3章介绍了 JDK 内部对并行程序开发的支持, 主要介绍 JUC (Java.util....

    Java实习生面试复习(八):volatile的学习

    我是一名很普通的双非大三学生。接下来的几个月内,我将坚持写博客...说起volatile,肯定少不了Java内存模型,Java内存模型(Java Memory Model,JMM)是Java虚拟机规范定义的,用来屏蔽掉java程序在各种不同的硬件和操作

    实战Java高并发程序设计(第2版)PPT模板.pptx

    4锁的优化及注意事项 4.1有助于提高锁性能的几点建议 4.2java虚拟机对锁优化所做的努力 4.3人手一支笔:threadlocal 4.4无锁 4.5有关死锁的问题 4.2Java虚拟机对锁优化所做的努力 4.3人手一支笔:ThreadLocal 4.4...

    线程安全之可见性揭秘-《云课堂》

    JVM运行时数据区和JMM(java内存模型)有什么区别? 1. JVM运行时数据区 是 由 《==Java虚拟机规范==》定义的 理解:不同的JVM厂商都必须 遵循 《==Java虚拟机规范==》进行开发 2. JMM是由 《java语言规范》定义的 ...

    国内面试leetcode-Android-Interview:Android-面试

    4、Jvm虚拟机:如执行过程、JMM模型、Java Gc回收原理、类加载器等。 5、数据结构和算法:LeetCode+剑指Offer。 6、Android基础:启动模式、动画、自定义View等。 7、Android进阶:进程间通信、Binder、AIDL、AMS/...

    leetcode下载-Android_Interviews:Android_Interviews

    4、Jvm虚拟机:比如执行过程、JMM模型、java的Gc回收原理、类加载器等等。 5、数据结构和算法:LeetCode + 剑指Offer。 6、Android基础:启动模式、动画、自定义View等等。 7、Android进阶:进程间通信、Binder、...

Global site tag (gtag.js) - Google Analytics