JMM内存模型、JMM内存间交互操作

2023-11-04

主内存与工作内存

在这里插入图片描述

JMM内存间交互操作

       关于主内存与工作内存之间具体的交互协议,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存这一类的实现细节,Java内存模型中定义了以下8种操作来完成。Java虚拟机实现时必须保证下面提及的每一种操作都是原子的、不可再分的(对于double和long类型的变量来说, load、store、read和write操作在某些平台上允许有例外)

       针对long和double型变量的特殊规则Java内存模型要求lock、unlock、read、load、assign、use、store、write这八种操作都具有原子性, 但是对于64位的数据类型(long和double),在模型中特别定义了一条宽松的规定:允许虚拟机将没有被volatile修饰的64位数据的读写操作划分为两次32位的操作来进行,即允许虚拟机实现自行选择是否要保证64位数据类型的load、store、read和write这四个操作的原子性,这就是所谓的“long和double的非原子性协定”(Non-Atomic Treatment of double and long Variables)。

       如果有多个线程共享一个并未声明为volatile的long或double类型的变量,并且同时对它们进行读取 和修改操作,那么某些线程可能会读取到一个既不是原值,也不是其他线程修改值的代表了“半个变 量”的数值。不过这种读取到“半个变量”的情况是非常罕见的,经过实际测试,在目前主流平台下商 用的64位Java虚拟机中并不会出现非原子性访问行为,但是对于32位的Java虚拟机,譬如比较常用的32 位x86平台下的HotSpot虚拟机,对long类型的数据确实存在非原子性访问的风险。从JDK 9起, HotSpot增加了一个实验性的参数-XX:+AlwaysAtomicAccesses(这是JEP 188对Java内存模型更新的 一部分内容)来约束虚拟机对所有数据类型进行原子性的访问。而针对double类型,由于现代中央处 理器中一般都包含专门用于处理浮点数据的浮点运算器(Floating Point Unit,FPU),用来专门处理 单、双精度的浮点数据,所以哪怕是32位虚拟机中通常也不会出现非原子性访问的问题,实际测试也 证实了这一点。笔者的看法是,在实际开发中,除非该数据有明确可知的线程竞争,否则我们在编写 代码时一般不需要因为这个原因刻意把用到的long和double变量专门声明为volatile。

  1. lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态。
  2. unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量 才可以被其他线程锁定。
  3. read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以 便随后的load动作使用。
  4. load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的 变量副本中。
  5. use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。
  6. assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
  7. store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随 后的write操作使用。
  8. write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的 变量中。

       如果要把一个变量从主内存拷贝到工作内存,那就要按顺序执行read和load操作,如果要把变量从 工作内存同步回主内存,就要按顺序执行store和write操作。注意,Java内存模型只要求上述两个操作 必须按顺序执行,但不要求是连续执行。也就是说read与load之间、store与write之间是可插入其他指令 的,如对主内存中的变量a、b进行访问时,一种可能出现的顺序是read a、read b、load b、load a。除此 之外,Java内存模型还规定了在执行上述8种基本操作时必须满足如下规则:

  • 不允许read和load、store和write操作之一单独出现,即不允许一个变量从主内存读取了但工作内存不接受,或者工作内存发起回写了但主内存不接受的情况出现。

  • 不允许一个线程丢弃它最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回 主内存。

  • 不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存 中。

  • 一个新的变量只能在主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load或 assign)的变量,换句话说就是对一个变量实施use、store操作之前,必须先执行assign和load操作。

  • 一个变量在同一个时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执 行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。

  • 如果对一个变量执行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作以初始化变量的值。

  • 如果一个变量事先没有被lock操作锁定,那就不允许对它执行unlock操作,也不允许去unlock一个 被其他线程锁定的变量。

  • 对一个变量执行unlock操作之前,必须先把此变量同步回主内存中(执行store、write操作)。

           这8种内存访问操作以及上述规则限定,再加上稍后会介绍的专门针对volatile的一些特殊规定,就已经能准确地描述出Java程序中哪些内存访问操作在并发下才是安全的。这种定义相当严谨,但也是极为烦琐,实践起来更是无比麻烦。可能部分读者阅读到这里已经对多线程开发产生恐惧感了,后来 Java设计团队大概也意识到了这个问题,将Java内存模型的操作简化为read、write、lock和unlock四种,但这只是语言描述上的等价化简,Java内存模型的基础设计并未改变,即使是这四操作种,对于普通用户来说阅读使用起来仍然并不方便。不过读者对此无须过分担忧,除了进行虚拟机开发的团队外,大概没有其他开发人员会以这种方式来思考并发问题,我们只需要理解Java内存模型的定义即可。

volatile

三重功效:

  1. 64位写入的原子性、
  2. 内存可见性
  3. 禁止重排序(实现有序性)。

happens-before

        介绍这种定义的一个等效判断原则——先行发生原则(Happens-Before),用来确定一个操作在并发环境下 是否安全的。

  • happen-before只确保如果A在B之前执行,则A的执行结果必须对B可见。
    • 单线程:as-if-serial
    • 对volatile变量的写,happen-before于后续对这个变量的读。 --编译器和cpu不能重排序
    • 对synchronized的解锁,happen-before于后续对这个锁的加锁。
    • 对final变量的写,happen-before于final域对象的读,happen-before于后续对final变量的读。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JMM内存模型、JMM内存间交互操作 的相关文章

  • 如何使用Spring WebClient进行同步调用?

    Spring Framework in 休息模板 https docs spring io spring framework docs current javadoc api org springframework web client R
  • 带有 Android 支持库 v7 的 Maven Android 插件

    我使用 maven android plugin 构建我的 android 应用程序 它依赖于 android 支持库 v4 和 v7 由于我没有找到如何从developer android com下载整个sdk 因此我无法使用maven
  • 如何将jscrollpane添加到jframe?

    我有以下源代码 有人可以给我建议如何将 jscrollpane 添加到 jframe 上吗 我尝试了几次将其添加到 jframe 但没有任何进展 它甚至没有显示 public class Form3 JFrame jframe new JF
  • 文本在指定长度后分割,但不要使用 grails 打断单词

    我有一个长字符串 需要将其解析为长度不超过 50 个字符的字符串数组 对我来说 棘手的部分是确保正则表达式找到 50 个字符之前的最后一个空格 以便在字符串之间进行彻底的分隔 因为我不希望单词被切断 public List
  • Logback:SizeAndTimeBasedRollingPolicy 不遵守totalSizeCap

    我正在尝试以一种方式管理我的日志记录 一旦达到总累积大小限制或达到最大历史记录限制 我最旧的存档日志文件就会被删除 当使用SizeAndTimeBasedRollingPolicy在 Logback 1 1 7 中 滚动文件追加器将继续创建
  • 为什么Iterator接口没有add方法

    In IteratorSun 添加了remove 方法来删 除集合中最后访问的元素 为什么没有add方法来向集合中添加新元素 它可能对集合或迭代器产生什么样的副作用 好的 我们开始吧 设计常见问题解答中明确给出了答案 为什么不提供 Iter
  • 如何检测图像是否像素化

    之前有人在 SO 上提出过这样的问题 在Python中检测像素化图像 https stackoverflow com questions 12942365 detecting a pixelated image in python还有关于q
  • 在 MongoDB 和 Apache Solr 之间同步数据的简单方法

    我最近开始使用 MongoDB 和 Apache Solr 我使用 MongoDB 作为数据存储 并且希望 Apache Solr 为我的数据创建索引 以实现应用程序中的搜索功能 经过一些研究 我发现 基本上有两种方法可以在 MongoDB
  • 从直方图计算平均值和百分位数?

    我编写了一个计时器 可以测量任何多线程应用程序中特定代码的性能 在下面的计时器中 它还会在地图中填充花费了 x 毫秒的调用次数 我将使用这张图作为我的直方图的一部分来进行进一步的分析 例如调用花费了这么多毫秒的百分比等等 public st
  • Eclipse - 安装新的 JRE (Java SE 8 1.8.0)

    我正在尝试安装 Java 8 到目前为止我所做的 安装最新版本的 Eclipse 下载并安装 Java SE 运行时环境 8http www oracle com technetwork java javase downloads jre8
  • Spring Data JPA:查询如何返回非实体对象或对象列表?

    我在我的项目中使用 Spring Data JPA 我正在演奏数百万张唱片 我有一个要求 我必须获取各种表的数据并构建一个对象 然后将其绘制在 UI 上 现在如何实现我的 Spring 数据存储库 我读到它可以通过命名本机查询来实现 如果指
  • 无法在 Java/Apache HttpClient 中处理带有垂直/管道栏的 url

    例如 如果我想处理这个网址 post new HttpPost http testurl com lists lprocess action LoadList 401814 1 Java Apache 不允许我这么做 因为它说竖线 是非法的
  • JAVA中遍历JSON数据

    我是 JSON 新手 我使用 HTTPUrlConnections 并在 JAVA 程序中获得一些响应 响应数据将类似于 data id 1 userId 1 name ABC modified 2014 12 04 created 201
  • 避免 Java 中的重复导入:继承导入?

    有没有办法 继承 导入 Example 常见枚举 public enum Constant ONE TWO THREE 使用此枚举的基类 public class Base protected void register Constant
  • 如何从 Ant 启动聚合 jetty-server JAR?

    背景 免责声明 I have veryJava 经验很少 我们之前在 Ant 构建期间使用了 Jetty 6 的包装版本来处理按需静态内容 JS CSS 图像 HTML 因此我们可以使用 PhantomJS 针对 HTTP 托管环境运行单元
  • 无需登录即可直接从 Alfresco 访问文件/内容

    我的场景是这样的 我有一个使用 ALFRESCO CMS 来显示文件或图像的 Web 应用程序 我正在做的是在 Java servlet 中使用用户名和密码登录 alfresco 并且我可以获得该登录的票证 但我无法使用该票证直接从浏览器访
  • 如何让 Emma 或 Cobertura 与 Maven 一起报告其他模块中源代码的覆盖率?

    我有一个带有 Java 代码的多模块 Maven 设置 我的单元测试在其中一个模块中测试多个模块中的代码 当然 这些模块具有相互依赖性 并且在测试执行之前根据需要编译所有相关模块中的代码 那么 如何获得整个代码库覆盖率的报告 注意 我不是问
  • 禁用 Android 菜单组

    我尝试使用以下代码禁用菜单组 但它不起作用 菜单项仍然启用 你能告诉我出了什么问题吗 资源 菜单 menu xml menu menu
  • 使用 Java https 上传到 Imgur v3 错误

    我目前正在尝试使用他们当前的 API v3 上传到 imgur 但是我不断收到错误 错误 javax net ssl SSLException 证书中的主机名不匹配 api imgur com imgur com OR imgur com
  • 何时在 hibernate 中使用 DiscriminatorValue 注解

    在 hibernate 中使用 DiscriminatorValue 注释的最佳场景是什么以及何时 这两个链接最能帮助我理解继承概念 http docs oracle com javaee 6 tutorial doc bnbqn html

随机推荐

  • 龙书笔记(9)

    chap 9 字体 生成和输出文本的3种方式 ID3DXFont CD3DFont D3DXCreateText 1 ID3DXFont接口 能处理一些复杂的字体和格式 但是速度略慢 创建ID3DXFont对象 D3DXFONT DESC
  • 爬虫:爬取Github项目结构、任意文件下载存储

    文章目录 场景描述 爬取 Github 项目的文件结构 爬取 Laravel 8 x 文件结构 编写脚本 访问 Github 连接超时 requests 读取时间超时 爬取脚本 任意文件下载脚本 场景描述 需求 发现 任意文件下载漏洞 后
  • C++ 结构体(struct)的继承

    C 中的struct对C中的struct进行了扩充 它已经不再只是一个包含不同数据类型的数据结构了 它已经获取了太多的功能 struct能包含成员函数吗 能 struct能继承吗 能 struct能实现多态吗 能 有很多人应该已经知道这样一
  • C++ 保留2位小数

    include
  • 索尼 toio™ 应用创意开发征文|小巧机器,大无限,探索奇妙世界

    文章目录 前言 微型机器人的未来 toio 小机器人简介 toio 小机器人 创新功能一览 toio 小机器人 多领域的变革者 toio 小机器人贪吃蛇游戏 代码实现 写在最后 前言 当我们谈到现代科技的创新时 往往会联想到复杂的机器和高级
  • VS2015新建项目时,左侧面板空白的解决方法

    VS2015新建项目时 左侧面板空白的解决方法 解决办法是 1 进入 C Users 当前用户名 一般为administrator AppData Local Microsoft VisualStudio 14 0 2 删除或重命名 Com
  • HDU 1007 Quoit Design竟然要分治

    Quoit Design Time Limit 10000 5000 MS Java Others Memory Limit 65536 32768 K Java Others Total Submission s 34742 Accept
  • Class 08 - 数据的读取和保存 & R语言中的管道(pip)功能

    Class 08 数据的读取和保存 R语言中的管道 pip 功能 数据的读取和保存 data 加载R中的数据集 readr 功能包介绍 readr 包中读取文件的函数 read csv 读取 csv 文件 readxl 包读取Excel文件
  • 小兔鲜儿 - 推荐模块

    目录 动态获取数据 静态结构 获取页面参数 获取数据 类型声明 热门推荐 渲染页面和Tab交互 热门推荐 分页加载 热门推荐 分页条件 type 和 interface 的区别 type 和 interface 的相似之处 type 的特点
  • C++ 静态库和动态库的区别

    库是C 中的函数集合 用于存放共享代码的 C 的库分为静态库和动态库 动态库将函数的声明和实现分开成两部分 分别存放在了两个文件中 而C 的函数声明就存放在了 lib 文件中 如果是静态库的话 lib 文件还会存放函数的代码本身和函数的实现
  • 基于 Jmeter 的轻量级云压测平台的原理与实现 :压测引擎

    目录 前言 平台的技术 平台的初衷 平台从开源开始到现在拥有了一些核心的功能 印象深刻的技术点 为什么执着于 Jmeter API 平台能带来什么 压测引擎 前端入口 Controller 必要的 Jmeter 配置准备 对 Jmeter
  • vue+file-saver+xlsx 封装导出Excel表格方法

    file saver xlsx 封装通用导出方法 安装插件依赖 npm i xlsx 0 17 0 npm i file saver 2 0 5 2 在utils文件夹中创建ExportExcel js文件 eslint disable i
  • write写文件乱码

    include
  • Python将图片转换为灰度图

    很多时候我们需要用到灰度图像 比如说在深度学习的训练中 有时候我们并不需要图片的颜色信息 然而我们日常环境下获得的通常都是彩色图像 所以需要将彩色图像转换成灰度图像 也就是从3个通道 RGB 转换成一个通道 from PIL import
  • 学会项目成本管理计算,PMP计算题就是送分题

    学会项目成本管理计算 PMP计算题就是送分题 PMP中的计算主要在 lt 项目成本管理 gt 的控制成本部分 服务于挣值管理 EVM Earned Value Management 挣值分析 EVA Earned Value Analysi
  • Android OpenGLES绘制yuv420纹理

    Android OpenGLES绘制yuv420纹理 曾大稳丶 关注 2018 07 16 11 31 字数 76 阅读 440评论 0喜欢 3 把shader代码写入raw里面 vertex shader glsl attribute v
  • keil编译错误:ERROR L250: CODE SIZE LIMIT IN RESTRICTED VERSION EXCEEDED

    出现这个错误 很多网上都说是没注册成功导致的 注册成功的话会在keil的菜单栏 help gt about 里看到如下的显示 我的keil里about显示注册成功了 但还是出现错误提示 ERROR L250 CODE SIZE LIMIT
  • AI 时代来临,这些 AI 工具让你的工作更加高效!

    在这篇文章中 我们将介绍一些有趣的人工智能应用 这些应用涵盖了不同的领域 包括图像生成 文本处理 决策辅助等 以下是这些应用的具体介绍和文本链接 AI 生成图标工具 iconifyai是一个AI生成App图标的产品 价格每15个图标约10美
  • codeforces 1186d D. Vus the Cossack and Numbers

    题意 和为0的n个double数 上下取整后和还为0的构造一个 首先都下取整 结果肯定 lt 0 和加起来再取绝对值num 则有num个数要上取整 那么小数部分为0的不变 不为0的挑num个上取整 其他的下取整 另外floor ceil r
  • JMM内存模型、JMM内存间交互操作

    主内存与工作内存 JMM内存间交互操作 关于主内存与工作内存之间具体的交互协议 即一个变量如何从主内存拷贝到工作内存 如何从工作内存同步回主内存这一类的实现细节 Java内存模型中定义了以下8种操作来完成 Java虚拟机实现时必须保证下面提