Java内存模型(JMM)

1.背景

JMM(Java Memory Model)的提出,主要基于以下的几种原因:

  1. 不同操作系统平台的内存模型不同,而Java又想做到Write Once Run Everywhere(即跨平台),那么必须要自己提供一套内存模型以屏蔽不同操作系统在内存模型方面的差异。
  2. 由于除了编译器层面可以进行指令重排外,处理器层面也可以,尽管指令重排在一定程度上能够提升程序运行的效率,但这仅限于单线程环境下,一旦处在多线程环境,这种指令重排带来的更多的是并发性问题(比如多级缓存与内存中的数据不一致),而Java又是多线程语言,那么就会存在多线程编程。为了保证开发者编写的并发程序能够按照预期安全地执行,Java必须提出一套并发编程相关的规范(比如happens-before原则)来解决多线程环境下的可能存在的并发性问题。

2.内容

2.1 内存规范

2.1.1 内存抽象

图片来源:https://www.cnblogs.com/theRhyme/p/9399881.html

  • 本地/工作内存:每个线程私有且独占,不可跨线程访问的物理内存区域。存放了共享变量的副本。
  • 主内存:线程间共享的逻辑内存区域(并不真实存在)。存放所有线程创建的实例对象,包括:成员变量、局部变量、类信息、常量、静态变量等。线程间通信必须借助主内存来进行。

2.1.2 内存操作

图片来源:https://blog.csdn.net/qq_39940205/article/details/120642838

下面的8种操作主要用于主内存与工作内存的数据交互:

  • 锁定(lock):将主内存中的一个共享变量标记为线程独享变量
  • 读取(read):将主内存中的一个共享变量传递到线程的工作内存中。
  • 载入(load):将从主存(通过read)读到的共享变量装载进工作内存中的相应的共享变量副本中。
  • 使用(use):将共享变量的副本传递给执行引擎,供其使用。(每次需要用到该变量时,都会执行该指令)
  • 赋值(assign):将从执行引擎接收到的结果值赋值给共享内存的副本。(每次的赋值操作均会调用该指令)
  • 存储(store):将共享变量的副本传递回主内存中。
  • 写入(write):将接收到的共享变量的副本(新修改的共享变量)写回主内存中的相应的共享变量中。
  • 解锁(unlock):将主内存中的一个共享变量线程独享变量的状态标记取消。

注:
JMM规范中并没有明确说明readstore将读到的共享变量(副本)存放在工作内存/主内存的什么地方,但是肯定没有存发在共享变量(副本)对应的槽位上(类似于找一个地方暂存一下数据的意思),因为它需要loadwrite指令正式存放到相应的变量槽位上去。

要求

  1. 同一时间,只能有一个线程持有某一共享变量的锁(通过lock指令获取),获得锁的线程可以多次加锁(同一个),但是释放锁时需要释放同等次数(类似于ReentrantLock)。
  2. 使用共享变量之前,必须先读取载入,即不允许在工作内存中读取一个凭空诞生(主内存中没有)的变量。
  3. 不允许写回一个没有赋值共享变量副本。(这样做你觉得有意义?😅)
  4. …(此处省略很多字)

2.2 并发规范

2.2.1 happends-before原则

一句话概括就是:前一个操作的结果对后一个操作是可见的,无论这两个操作是否处在同一个线程里。

8项原则

  1. 程序顺序原则:在同一个线程内的代码中,写在前面的代码happens-before写在后面的代码
  2. 锁规则加锁happens-before释放锁
  3. volatile规则:对于一个volatile变量的写操作happens-before volatile变量的读操作。(该原则并不是说你只能先写后读一个volatile变量,而是说,前一个操作如果是写入volatile变量的操作,那么该volatile变量的新值对于后续的volatile读操作一定是可见的)
  4. start规则线程的start()动作happens-before线程内的每个动作
  5. join规则线程内的所有动作happens-before线程的join()动作
  6. interrupt规则对线程调用interrupt() happens-before线程自己检测到中断事件的发生
  7. finalize规则一个对象的构造函数的执行、结束和返回happens-before这个对象finalize()方法的开始
  8. 传递性A happens-before BB happens-before C,那么就有A happens-before C

3.注意事项

3.1 JMMJVM内存结构的区别

  • JMM:与Java并发编程相关,抽象了线程与主内存的关系,规定了并发相关的原则和规范,以简化多线程编程,增强程序的可移植性。
  • JVM内存结构:与JVM运行时区域相关,定义了JVM如何分区存储不同类型的数据。

3.2 happens-beforeJMM的关系

图片来源:http://wxweven.win/2016/10/15/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Java%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B%EF%BC%88%E4%B8%80%EF%BC%89%E2%80%94%E2%80%94%E5%9F%BA%E7%A1%80%E7%AF%87/
JMM通过自行禁用处理器的若干重排序规则或者直接禁用某种类型的处理器来实现它向程序猿发出的happens-before几点保证,因为处理器的重排序规则在并发环境下可能会产生未知差错从而使得happens-before失去保证,所以必须要根据实际的运行情况进行适当的禁用。

4.补充

4.1 并发编程的三大重要特性

  1. 原子性:一次操作或者多个操作要么全都执行,要么全都不执行。(这里不包括执行失败后回滚的情况,即并发编程的原子性 ≠ 事务性的原子性)
  2. 可见性:当一个线程对某一个共享变量进行了修改,那么其他线程将能够立即看到修改后的新值。
  3. 有序性:因为编译器和处理器对代码进行指令重排序的缘故,你所编写的代码的顺序不一定就是代码实际的执行顺序。

参考文档

JMM(Java 内存模型)详解

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

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

相关文章

断开自定义模块与自定义库的链接

断开自定义模块与自定义库的链接 1、断开模块与库的链接 1、断开模块与库的链接 如果摸个库文件添加到模型中,无法“Disable Link”时,可以使用save_system命令进行断开到模型中用户定义的库模块的链接; 参考链接: 传送门 save…

docker占用磁盘空间大小排查

首先进入到 /var/lib/docker/overlay2 目录下,查看谁占用的较多 cd /var/lib/docker/overlay2/du -s ./* | sort -rn | more再通过目录名查找容器名 docker ps -q | xargs docker inspect --format {{.State.Pid}}, {{.Id}}, {{.Name}}, {{.GraphDriver.Data.WorkDir}} | gre…

《C语言深度解剖》(16):C语言的文件读写操作

🤡博客主页:醉竺 🥰本文专栏:《C语言深度解剖》 😻欢迎关注:感谢大家的点赞评论关注,祝您学有所成! ✨✨💜💛想要学习更多C语言深度解剖点击专栏链接查看&…

n后问题 回溯笔记

问题描述 在nn格的棋盘上放置彼此不受攻击的n个皇后。 按照国际象棋的规则,皇后可以攻击与之处在同 一行或同一列或同一斜线上的棋子。n后问题等价于在nn格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。 代码 import java.uti…

在 iCloud.com 上导入、导出或打印联系人

想将iPhone上的电话本备份一份到本地电脑上,发现iTunes好像只是音乐播放了,不再支持像电话本等功能,也不想通过其他第三方软件,好在可以通过iCloud进行导入导出。下面只是对操作过程进行一个图片记录而已,文字说明可以…

总是不能盈利?试着用这两个观点去学习现货白银的技巧

一进入现货白银市场,投资者都想着如何去找到现货白银交易的机会,学习现货白银投资的方法。其实这些都是手段,而最终的目的还是为我们的盈利服务。而对于盈利来说,其实胜率和风险报酬比才是影响盈利的重要因素,我们带着…

centos8stream 编译安装 php-rabbit-mq模块

官方GitHub:https://github.com/php-amqp/php-amqp 环境依赖安装 dnf install cmake make -y 1.安装rabbitmq-c cd /usr/local/src/ wget https://github.com/alanxz/rabbitmq-c/archive/refs/tags/v0.14.0.tar.gz tar xvf v0.14.0.tar.gz cd rabbitmq-c-0.14.0/…

不用写采集规则的网页采集软件

传统的网页采集工具采集网页数据,需要查看和研究网页代码,编写复杂繁琐的采集规则,对于有技术基础的人,配置一个采集规则也要花费不少时间,更何况对于不懂技术的普通用户来说,简直是一项不太可能完成的任务…

服务器内存与CPU要占用多少才合理?

一 通常服务器内存占用多少合理?cpu占用多少才合理? 1 通常配置范围建议: 建议CPU使用率不高于80%;内存使用率不高于80%; 注意:具体情况还需要根据服务器的实际负载和应用场景来判断。 2 内存使用率&…

备受推崇的公司文件加密文件推荐榜单

迄今为止,加密依然是最有效的用于保护数据、通讯安全的手段之一 在数字化时代,文件加密软件成为了保护个人和企业数据安全的重要工具。随着技术的不断进步,市场上涌现出了众多优秀的文件加密软件。 以下十款文件加密软件因其出色的性能、易…

新疆 | 金石商砼效率革命背后的逻辑

走进标杆企业,感受名企力量,探寻学习优秀企业领先之道。 本期要跟砼行们推介的标杆企业是新疆砼行业的龙头企业:新疆兵团建工金石商品混凝土有限责任公司(以下简称:新疆金石)。 从年产80万方到120万方&am…

【Python编程】给电脑安装最新的 Python3.12.3

笔者最近更换了新的Win11系统,安装最新的Python版本(3.12.3)尝尝鲜。据说这个版本存在一些漏洞,笔者将后续更新编程过程中的相关问题(如果有)。Python3.12.3的安装过程比较简单,在此进行说明。 …

MyBatisPlus的简单入门

文章目录 1.MybatisPlus的简介2.创建SpringBoot工程3.编写测试类 1.MybatisPlus的简介 MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在:简化开发、提高效率。 它对应的官方网址:链接 2.创建Sprin…

朋友圈定时发送设置

人日常中不可缺少的一件事,同时也是企业用来触达客户的重要渠道,下面一起来了解下微信朋友圈怎么定时发送呢?

ROS2贪吃龟练习工程

本文是ROS2基础知识的综合小应用,练习如何创建工作包,创建Node,定义Topic和Service,以及通过LaunchFile启动多个节点。基础知识可以参考:ROS2基础编程,ROS2 Topics和Services,ROS2 LaunchFile和…

python使用多种方法计算列表元素平方的技巧

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、使用列表推导式进行元素平方 二、使用map函数进行元素平方 三、循环遍历列表进行元素平…

外卖系统开发的技术栈和架构设计

开发一个功能完备且高效的外卖系统,需要选择合适的技术栈并设计良好的系统架构。本文将详细介绍外卖系统开发过程中常用的技术栈以及架构设计的关键要点,帮助开发者构建一个高性能、可扩展且易维护的外卖平台。 1. 技术栈选择 选择合适的技术栈是开发…

工控一体机5寸显示器电容触摸屏(YA05WK)产品规格说明书

如果您对工控一体机有任何疑问或需求,或者对如何集成工控一体机到您的业务感兴趣,可移步控芯捷科技。 一、硬件功能介绍 YA05WK是我公司推出的一款新型安卓屏,4核Cortex-A7 架构,主频1.2GHz的CPU。采用12V供电,标配5寸…

UML 在 vs-code上的快速使用

UML 在 vs-code上的快速使用 1.软件准备工作2.创建第一张甘特图2.1 创建 UML文件: xxxx. puml2.2 输入甘特图代码2.3 VS code 生成甘特图 结束 。 1.软件准备工作 使用的软件为:VS CODE使用插件 : PluntUML2.创建第一张甘特图 2.1 创建 UML文件: xxxx. …

认识NoSql

SQL是结构化的,NoSql是非结构化的 SQL是关联的: Nosql是无关联的: SQL采用的是SQL查询: 语法固定,好处是:只要是关系型数据库(Mysql,Oracle),都能够使用相同的语句进行查…