【Java并发系列】--Java内存模型

时间:2022-03-27 03:05:43

Java内存模型

1 基本概念

程序:代码,完成某一个任务的代码序列(静态概念)

进程:程序在某些数据上的一次运行(动态)

线程:一个进程有一个或多个线程组成(占有资源的独立单元)

2 JVM与线程

jvm启动时期

类被调用: JVM线程启动——> 启动其他线程(main)

3 jvm内存区域(运行时数据区)

【Java并发系列】--Java内存模型

Java虚拟机会在程序运行时将内存自动划分为以上几个区域,每个区域都有其作用及创建和销毁时机。

  • 方法区:(共享区域)存储已被加载的类信息、常量、静态变量(static)、即时编译器编译后的代码(JIT)等数据。根据Java 虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError 异常。值得注意的是在方法区中存在一个叫运行时常量池(Runtime Constant Pool)的区域,它主要用于存放编译器生成的各种字面量和符号引用,这些内容将在类加载后存放到运行时常量池中,以便后续使用。

  • 堆区(Heap):(共享区域)存放类实例对象。GC主要管理区域,故有时也被称为:GC堆(OOM)如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常。

  • 虚拟机栈区(VM stack):Java方法在运行时的内存模型,其大小固定可自行设定。(OOM:**该区域的内存溢出主要指整个VM stack的溢出,单个栈帧不会溢出,栈帧会根据方法执行需要的大小来申请栈帧空间 ** )

【Java并发系列】--Java内存模型

  • 本地方法栈(Native Method Stack):本地方法栈属于线程私有的数据区域,这部分主要与虚拟机用到的 Native 方法相关,一般情况下,我们无需关心此区域。

  • 程序计数器(PC Register):Java线程私有数据,该数据就是执行下一条指令的地址。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

4 Java内存模型 (Java memory model)JMM(规范,抽象的模型)

【Java并发系列】--Java内存模型

JMM不真实存在只是一种抽象概念,它描述了一种规则,用来规范程序中数据的访问方式。

1)主内存:存放共享的信息(方法区和堆区中的数据)。

2)工作空间:存放私有信息(虚拟机栈区,本地方法栈,程序计数器中的数据)。基本数据类型,直接分配到工作空间;引用类型:引用的地址存放在工作内存中,引用对象存放在堆中。实际数据在主存中。

3)工作方式:

  • 1 线程修改私有数据:直接修改工作空间数据
  • 2 线程修改共享数据:数据先把主内存的数据复制到工作空间,然后在工作空间修改数据,修改完成后把工作空间的数据刷新到主内存中。

5 硬件内存架构与Java内存模型

1) 硬件架构

【Java并发系列】--Java内存模型

该架构描述了cpu与内存操作,在cpu工作时直接使用寄存器中的数据,因为寄存器存在于cpu的内部而且访问速度在内存设备中最快。但是由于寄存器小,不能存放大量数据。所以数据一般存放在内存中,但是内存的访问速度太慢,导致CPU在处理指令时往往花费很多时间在等待内存做准备工作 ,所以在寄存器和内存之间又加入了缓存,缓存比较小,但访问速度比主内存快得多 。如果CPU总是访问主内存中的同一址地的数据,很容易影响CPU执行速度,此时缓存就可以把从内存提取的数据暂时保存起来,如果寄存器要取内存中同一位置的数据,直接从缓存中提取,无需直接从主内存取。需要注意的是,寄存器并不每次数据都可以从缓存中取得数据,万一不是同一个内存地址中的数据,那寄存器还必须直接绕过缓存从内存中取数据。所以并不每次都得到缓存中取数据,这种现象有个专业的名称叫做缓存的命中率,从缓存中取就命中,不从缓存中取从内存中取,就没命中,可见缓存命中率的高低也会影响CPU执行性能,这就是CPU、缓存以及主内存间的简要交互过程,总而言之当一个CPU需要访问主存时,会先读取一部分主存数据到CPU缓存(当然如果CPU缓存中存在需要的数据就会直接从缓存获取),进而在读取CPU缓存到寄存器,当CPU需要写数据到主存时,同样会先刷新寄存器中的数据到CPU缓存,然后再把数据刷新到主内存中。

  • cpu缓存的一致性问题:并发处理不同步
  • 解决方案:
    • 1 总线加锁:
      • 缺点:降低cpu的吞吐量。不推荐该方案
    • 2 缓存一致性协议(MESI协议):
      • 当cpu在cache操作数据时,如果该数据是共享变量,数据在cache中读到寄存器中,再进行修改,并更新内存数据。
      • cache LINE置无效,其他的cpu不会从的cache中读数据,而是从内存中读数据

2) Java线程与硬件处理器

【Java并发系列】--Java内存模型

​ Java线程的实现是基于一对一的线程模型,所谓的一对一模型,实际上就是通过语言级别层面程序去间接调用系统内核的线程模型,即我们在使用Java线程时,Java虚拟机内部是转而调用当前操作系统的内核线程来完成当前任务 。内核线程(Kernel-Level Thread,KLT),它是由操作系统内核(Kernel)支持的线程,这种线程是由操作系统内核来完成线程切换,内核通过操作调度器进而对线程执行调度,并将线程的任务映射到各个处理器上。每个内核线程可以视为内核的一个分身,这也就是操作系统可以同时处理多任务的原因。

3)Java内存模型与硬件架构的关系

【Java并发系列】--Java内存模型

​ JMM只是一种抽象概念对硬件的实际存在不影响,而JMM中工作空间和主内存中的数据即可存在与寄存器中由可能存在于缓存(cache)中还可能存在于主内存(RAM)中,所以JMM与内存硬件架构是一种相互交叉的关系。

4)Java内存模型的必要性

​ Java内存模型的作用:规范内存数据与工作空间数据的交互

6 并发编程的三个重要特性

原子性:指的是一个操作是不可中断的 ,不可分割。如x=10,就具有原子性,因为只有一步把10写入变量x中的操作。而y=x就不具有原子性,因为它分为把数据x读到工作空间,把x的值写入y两步操作。

可见性:线程只能操作自己工作空间中的数据,自己工作空间中的数据只对自己可见不对其他线程可见。

有序性:程序的执行顺序不一定是程序的书写顺序。在看似顺序执行的Java代码在JVM中可能出现优化,编译器或者CPU对操作指令出现重新排序。

出现有序性的原因:

  • 编译重排序:在编译其为优化代码而对程序进行重排序
  • 指令重排序:在cpu执行过程中,对指令进行重排序,从而降低指令的执行时间,提高代码执行效率。

无论是编译重排序还是指令重排序都要遵循as-if-seria原则

as-if-seria:即不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。

7 JMM对三个特征的保证

1)JMM与原子性

因为多个原子性操作组合到一起是没有原子性的,所以为了保证多个原子性操作组合在一起的原子性;JMM保证其原子性的方式。

  • 通过关键字Synchronized,
  • JUC中的Lock类中的lock()方法

2)JMM与可见性

JMM保证可见性的方式:

  • Volatile:在JMM模型上实现MESI协议
  • Synchronized:加锁
  • JUC:JUC中的Lock类中的lock()方法

3)JMM与有序性

JMM保证有序性的方式:

  • Volatile

  • Synchronized

  • Happens-before原则:

    a.程序次序原则:程序次序改变不影响程序的结果

    b.锁定原则:后一次加锁必须等待前一次解锁

    c.Volatile原则:Volatile关键字修饰的内容,在程序中的位置不能改变

    d.传递原则:A—>B---->C ===> A---->C

因为篇幅原因关于Synchronized,Volatile关键字和JUC有个内容在后续文章中给出。

【Java并发系列】--Java内存模型的更多相关文章

  1. Java并发编程、内存模型与Volatile

    http://www.importnew.com/24082.html  volatile关键字 http://www.importnew.com/16142.html  ConcurrentHash ...

  2. Java 并发系列之二:java 并发机制的底层实现原理

    1. 处理器实现原子操作 2. volatile /** 补充: 主要作用:内存可见性,是变量在多个线程中可见,修饰变量,解决一写多读的问题. 轻量级的synchronized,不会造成阻塞.性能比s ...

  3. Java并发编程-Java内存模型

    JVM内存结构与Java内存模型经常会混淆在一起,本文将对Java内存模型进行详细说明,并解释Java内存模型在线程通信方面起到的作用. 我们常说的JVM内存模式指的是JVM的内存分区:而Java内存 ...

  4. Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析

    学习Java并发编程不得不去了解一下java.util.concurrent这个包,这个包下面有许多我们经常用到的并发工具类,例如:ReentrantLock, CountDownLatch, Cyc ...

  5. Java并发系列[5]----ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...

  6. java中JVM虚拟机内存模型详细说明

    java中JVM虚拟机内存模型详细说明 2012-12-12 18:36:03|  分类: JAVA |  标签:java  jvm  堆内存  虚拟机  |举报|字号 订阅     JVM的内部结构 ...

  7. Java虚拟机学习 - 体系结构 内存模型

    一:Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代” .“非堆”, 它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内存区域.默认最小值为16MB,最 ...

  8. Java虚拟机学习 - 体系结构 内存模型(1)

    一:Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代" ."非堆",  它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内 ...

  9. Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式

    在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...

  10. Java并发系列&lbrack;3&rsqb;----AbstractQueuedSynchronizer源码分析之共享模式

    通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...

随机推荐

  1. android studio上的基本动画实现(第一篇)

    hello,各位小伙伴们,在很多小伙伴们刚刚开始学习android的时候,常常会有一些project里面需要有一些基本动画的插入,那么具体是要怎么实现呢?我们接下一起分析一下在android中的几种基 ...

  2. Android开发 代替 &OpenCurlyDoubleQuote;&lpar;XXXX&rpar;findViewById&lpar;&rpar;”

    public class NActivity extends Activity{ protected void onCreate(Bundle savedInstanceState){ setCont ...

  3. P&comma;NP&comma;NPC&comma;NPC-HARD

    P: 能在多项式时间内解决的问题 NP: 不能在多项式时间内解决或不确定能不能在多项式时间内解决,但能在多项式时间验证的问题 NPC: NP完全问题,所有NP问题在多项式时间内都能约化(Reducib ...

  4. OpenGL学习——基本概念和坐标变换

    基本概念 基本功能:几何图形.变换.着色.光照.贴图 高级功能:曲面图元.光栅操作.景深.shader编程   状态机 先设置状态参数:多边形.顶点列表.填充颜色.纹理.混合模式.坐标系 再调用绘图指 ...

  5. (二)如何在&period;net中使用Redis

    Step1:使用NuGet工具安装Redis C# API,这里有多个API我们可以使用其中一个:

  6. 《STL源码剖析》chapter2空间配置器allocator

    为什么不说allocator是内存配置器而说是空间配置器,因为空间不一定是内存,也可以是磁盘或其他辅助介质.是的,你可以写一个allocator,直接向硬盘取空间.sgi stl提供的配置器,配置的对 ...

  7. Mysql 锁粒度

    表锁: 表锁是mysql 中最几本的锁策略,并且是开销最小的策略:它会锁定整张表. 一个用户在对表进行锁操作(增,删,改)前,首先要获得写锁,这会阻塞其他用户对该表的所有读写操作.只有没有写锁时,其他 ...

  8. 老李分享:Uber究竟是用什么开发语言? 2

    Uber的任务分派系统是运行在Node上,这是一个运行在服务器端的JavaScript平台.当一个客户打开app或者网站来进行车辆预定或者调用其他的API来查看可用车辆信息的时候,大部分的这些服务都是 ...

  9. php的api及登录的权限验证

    类,库,接口(APi),函数,这些概念都是根据问题规模的大小来界定的.一个很小的问题肯定没有必要写成一个库,只需要写几句话就行了. 但是比如一个登录验证,这个功能很强大,很通用,可能前台后台都需要用到 ...

  10. 关于&lt&semi;T&gt&semi; T&lbrack;&rsqb; toArray&lpar;T&lbrack;&rsqb; a&rpar; 方法

    http://mopishv0.blog.163.com/blog/static/5445593220101016102129741/ private List<String> uploa ...