什么是JMM模型

news2024/9/22 15:42:46

什么是JMM模型?

Java内存模型(Java Memory Model简称JMM)是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),用于存储线程私有的数据,而Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝的自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,工作内存中存储着主内存中的变量副本拷贝,前面说过,工作内存是每个线程的私有数据区域,因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成。

JMM不同于JVM内存区域模型

JMM与JVM内存区域的划分是不同的概念层次,更恰当说JMM描述的是一组规则,通过这组规则控制程序中各个变量在共享数据区域和私有数据区域的访问方式,JMM是围绕原子性,有序性、可见性展开。JMM与Java内存区域唯一相似点,都存在共享数据区域和私有数据区域,在JMM中主内存属于共享数据区域,从某个程度上讲应该包括了堆和方法区,而工作内存数据线程私有数据区域,从某个程度上讲则应该包括程序计数器、虚拟机栈以及本地方法栈。

线程,工作内存,主内存工作交互图(基于JMM规范):

主内存

主要存储的是Java实例对象,所有线程创建的实例对象都存放在主内存中,不管该实例对象是成员变量还是方法中的本地变量(也称局部变量),当然也包括了共享的类信息、常量、静态变量。由于是共享数据区域,多条线程对同一个变量进行访问可能会发生线程安全问题。

工作内存

主要存储当前方法的所有本地变量信息(工作内存中存储着主内存中的变量副本拷贝),每个线程只能访问自己的工作内存,即线程中的本地变量对其它线程是不可见的,就算是两个线程执行的是同一段代码,它们也会各自在自己的工作内存中创建属于当前线程的本地变量,当然也包括了字节码行号指示器、相关Native方法的信息。注意由于工作内存是每个线程的私有数据,线程间无法相互访问工作内存,因此存储在工作内存的数据不存在线程安全问题。
根据JVM虚拟机规范主内存与工作内存的数据存储类型以及操作方式,对于一个实例对象中的成员方法而言,如果方法中包含本地变量是基本数据类型(boolean,byte,short,char,int,long,float,double),将直接存储在工作内存的帧栈结构中,但倘若本地变量是引用类型,那么该变量的引用会存储在功能内存的帧栈中,而对象实例将存储在主内存(共享数据区域,堆)中。但对于实例对象的成员变量,不管它是基本数据类型或者包装类型(Integer、Double等)还是引用类型,都会被存储到堆区。至于static变量以及类本身相关信息将会存储在主内存中。需要注意的是,在主内存中的实例对象可以被多线程共享,倘若两个线程同时调用了同一个对象的同一个方法,那么两条线程会将要操作的数据拷贝一份到自己的工作内存中,执行完成操作后才刷新到主内存

模型如下图所示

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

通过对前面的硬件内存架构、Java内存模型以及Java多线程的实现原理的了解,我们应该已经意识到,多线程的执行最终都会映射到硬件处理器上进行执行,但Java内存模型和硬件内存架构并不完全一致。对于硬件内存来说只有寄存器、缓存内存、主内存的概念,并没有工作内存(线程私有数据区域)和主内存(堆内存)之分,也就是说Java内存模型对内存的划分对硬件内存并没有任何影响,因为JMM只是一种抽象的概念,是一组规则,并不实际存在,不管是工作内存的数据还是主内存的数据,对于计算机硬件来说都会存储在计算机主内存中,当然也有可能存储到CPU缓存或者寄存器中,因此总体上来说,Java内存模型和计算机硬件内存架构是一个相互交叉的关系,是一种抽象概念划分与真实物理硬件的交叉。(注意对于Java内存区域划分也是同样的道理)

JMM存在的必要性

在明白了Java内存区域划分、硬件内存架构、Java多线程的实现原理与Java内存模型的具体关系后,接着来谈谈Java内存模型存在的必要性。由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),用于存储线程私有的数据,线程与主内存中的变量操作必须通过工作内存间接完成,主要过程是将变量从主内存拷贝的每个线程各自的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,如果存在两个线程同时对一个主内存中的实例对象的变量进行操作就有可能诱发线程安全问题。

假设主内存中存在一个共享变量x,现在有A和B两条线程分别对该变量x=1进行操作,A/B线程各自的工作内存中存在共享变量副本x。假设现在A线程想要修改x的值为2,而B线程却想要读取x的值,那么B线程读取到的值是A线程更新后的值2还是更新前的值1呢?答案是,不确定,即B线程有可能读取到A线程更新前的值1,也有可能读取到A线程更新后的值2,这是因为工作内存是每个线程私有的数据区域,而线程A变量x时,首先是将变量从主内存拷贝到A线程的工作内存中,然后对变量进行操作,操作完成后再将变量x写回主内,而对于B线程的也是类似的,这样就有可能造成主内存与工作内存间数据存在一致性问题,假如A线程修改完后正在将数据写回主内存,而B线程此时正在读取主内存,即将x=1拷贝到自己的工作内存中,这样B线程读取到的值就是x=1,但如果A线程已将x=2写回主内存后,B线程才开始读取的话,那么此时B线程读取到的就是x=2,但到底是哪种情况先发生呢?

如以下示例图所示案例:

以上关于主内存与工作内存之间的具体交互协议,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步到主内存之间的实现细节,Java内存模型定义了以下八种操作来完成。

(1)lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态

(2)unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

(3)read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用

(4)load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中

(5)use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎

(6)assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量

(7)store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作

(8)write(写入):作用于工作内存的变量,它把store操作从工作内存中的一个变量的值传送到主内存的变量中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/182056.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

11. 线程本地变量ThreadLocal的使用

1. 对ThreadLocal的理解 ThreadLocal,有人称它为线程本地变量,也有人称它为线程本地存储,其实表达的意思是一样的。ThreadLocal在每一个变量中都会创建一个副本,每个线程都可以访问自己内部的副本变量。 在多线程环境下&#xff…

tomcat 的并发能力分析

tomcat 参考:Tomcat的3个参数acceptCount、maxConnections、maxThreads Tomcat 的核心组件 Tomcat 由 2 大核心组件组成:Connector、Container Tomcat 处理请求的过程 请求在 tomcat 服务器的处理过程(BIO 模式) 客户端与服务…

嵌入式串行通信协议

嵌入式系统中,不同芯片之间通常使用串行总线的方式进行连接,根据器件行业规范、应用场景,不同芯片通常选择不同的串行通信接口进行通信。常用的串行通信接口有:1-Wire、I2C、SPI、UART。 一、1-Wire 1-wire单总线是Maxim的全资子…

bodgeito通关教程

6.bodgeito通关教程 进入网站整体浏览网页 点击页面评分进入关卡 一般搭建之后这里都是红色的&#xff0c;黄色是代表接近&#xff0c;绿色代表过关 首先来到搜索处本着见框就插的原则 构造payload输入 <script> alert(/xss/)</script>成功弹窗xss&#xff0c;发…

Redis数据库

1.Redis简介 1.1Redis简介 Redis 是当前互联网世界最为流行的 NoSQL&#xff08;Not Only SQL&#xff09;数据库。NoSQL 在互联网系统中的作用很大&#xff0c;因为它可以在很大程度上提高互联网系统的性能。 Redis 具备一定持久层的功能&#xff0c;也可以作为一种缓存工具…

c++实现堆排序

看了一下优先队列&#xff0c;查了一下堆排序。堆排序主要就是建最大堆&#xff08;最小堆&#xff09;和交换2个操作。如果建的是最大堆&#xff0c;那么交换的时候&#xff0c;父节点就和最大的子节点比较&#xff0c;如果它比最大的子节点还大&#xff0c;那就不用比了。因为…

STM32MP157开发板Linux+Qt项目实战:智能猫眼

stm32mp157开发板FS-MP1A是华清远见自主研发的一款高品质、高性价比的Linux单片机二合一的嵌入式教学级开发板。开发板搭载ST的STM32MP157高性能微处理器&#xff0c;集成2Cortex-A7核和1个Cortex-M4 核&#xff0c;A7核上可以跑Linux操作系统&#xff0c;M4核上可以跑FreeRTOS…

docker 搭建postgres 主从 pgadmin

准备工作 创建一个docker bridge 网路用于测试 docker network create -d bridge --subnet 192.168.0.0/24 --gateway 192.168.0.1 pgnetwork # 查看 docker network ls 设置了网段为 192.168.0.0&#xff0c;规划主从库IP端口如下&#xff1a; 主库 192.168.0.101:5432 从库…

Ubuntu16.04安装深度学习环境(CUDA9.2+PyTorch0.4.1+Python2.7)

之前已经安装好了显卡驱动&#xff0c;接着就可以安装CUDA了于是又找了好几篇文章进行参考&#xff1a;https://zhuanlan.zhihu.com/p/361190040https://blog.csdn.net/qq_43665602/article/details/125752433https://blog.csdn.net/myg22/article/details/84029924https://blo…

二、数据缓存

文章目录数据缓存1.标准缓存流程2.缓存更新一致性3.缓存穿透解决方案缓存空对象布隆过滤器4.缓存雪崩解决方案5.缓存击穿解决方案互斥锁逻辑过期6.使用函数式接口封装工具类学习 黑马点评项目整理总结: https://www.bilibili.com/video/BV1cr4y1671t/?vd_source5f3396d3af2c39…

webpack项目配置

30.webpack——webpack5新特性&#xff08;启动、持久化缓存、资源模块、URIs、moduleIds和chunkIds、tree shaking、nodeJs的polyfill被移除、模块联邦&#xff09;_俞华的博客-CSDN博客_chunkids webpack和vite的区别 - 简书 vite介绍 &#xff5c; 与其他构建工具做比较&…

【ONE·C || 字符串和内存函数】

总言 C语言&#xff1a;字符串和内存函数使用介绍。 文章目录总言1、求字符串长度&#xff1a;strlen1.1、基本介绍1.2、演示说明1.2.1、strlen输出1.2.2、strlen返回值1.3、模拟实现strlen1.3.1、计数器写法1.3.2、递归写法1.3.3、指针-指针写法2、长度不受限制的字符串函数2.…

educoder数据结构 图 无错AC代码版

目录 第1关&#xff1a;实现图的宽度优先遍历 任务描述 相关知识 编程要求 测试说明 输入输出格式说明&#xff1a; 样例输出 Ac_Code 第2关&#xff1a;实现图的深度优先遍历 任务描述 相关知识 测试说明 输入输出格式&#xff1a; 样例输出 AC_Code 第1关&am…

2023年flag

开头总是让人那么茫然无措&#xff0c;在这里记录梳理上一年。以期找到前进的方向&#xff0c;迈开新一年的第一步&#xff0c;然后不断前行。 回顾上一年 首先想到的第一件事&#xff0c;11月换了个工作依然是Java开发10月份准备了软件工程中级考试并考过读了几本技术的书籍…

【设计模式】我终于读懂了享元模式。。。

祝大家开工大吉&#x1f9e7;&#x1f9e7;&#x1f9e7;&#xff01;&#xff01;主页有红包哦 点这里 文章目录祝大家开工大吉&#x1f9e7;&#x1f9e7;&#x1f9e7;&#xff01;&#xff01;主页有红包哦 [点这里](https://blink.csdn.net/details/1469531)&#x1f9e7;…

Python基础学习 -- 进程锁

一、join函数的作用1、等子进程执行完&#xff0c;主进程再结束2、将子进程都存储到一个列表&#xff0c;每个子进程都调用一下join方法if __name__"__main__":print("我是主线程")stime.time()a[2,3,4]b[] #存储创建好的进程for i in a:pProcess(targetfu…

入门算法,这篇文章你得看!(java、算法基础、常用算法)

想用Java快速入门算法&#xff1f;这篇文章你得看&#xff01; 提示&#xff1a;本文章适合想要入门算法&#xff0c;并且想 “快速” 达到一定成果的同学们阅读~ 文章非常非常非常长&#xff08;可能是你见过最长的博客&#xff09;&#xff01;&#xff01;&#xff01; 阅读…

Authing 身份云入选《数字身份治理与管理(IGA)应用实践指南》报告

身份是物理实体映射在网络空间的一串数字代码&#xff0c;是数字世界的通行证。掌控了统一的权威数字身份就等同掌控了实体在数字空间的行为。网络业务的快速发展&#xff0c;使业务与安全深度融合到一起&#xff0c;并使数字身份成为数字化经济建设的重要基石。同一实体可以更…

【数据结构初阶】第一篇——算法性能分析

算法效率 什么是大O 时间复杂度分析 概念 大O渐进表示法 不同数据规模的差异 复杂表达式的化简 O(logn)中的log是以什么为底? 案例分析 算法为什么会超时 递归算法的时间复杂度 空间复杂度分析 概念 案例分析 递归算法的性能分析 代码的内存消耗 算法效率 算法…

如何使用VMware虚拟机(带你快速了解)

前言 &#x1f4dc; “作者 久绊A” 专注记录自己所整理的Java、web、sql等&#xff0c;IT技术干货、学习经验、面试资料、刷题记录&#xff0c;以及遇到的问题和解决方案&#xff0c;记录自己成长的点滴 目录 前言 一、什么是虚拟机 二、VMware的简介 1、大概介绍 2、详…