JMM到底如何理解?

JMM到底如何理解?JMM与MESI到底有没有关系? - 知乎 (zhihu.com)

        不同架构的物理机器可以拥有不一样的内存模型,而JVM 也实现了“Java内存模型”,来屏蔽各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果。(也是Java实现跨平台性的一个重要实现)

JMM 是 JVM 自己抽象实现的,用来实现Java的多线程,所以JMM 的实现紧紧围绕并发编程的三大特性:原子性、可见性、有序性 来实现。

JMM 规定了 工作内存 + 主内存 的一种模型(用于Java多线程之间的通信)。把线程之间所有的共享变量都存储到主内存中,每个线程都有自己的工作内存,线程的工作内存中使用的共享变量都是来自主内存中的副本,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的数据,是否实时触发回写机制(将工作内存中的修改及时同步到主内存)来实现各线程对共享变量的一致性(可见性)由这个共享变量是否被volatile修饰来决定。

在说三大特性之前先介绍一下JMM 工作内存和主内存之间是如何进行数据交互的 

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

·unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量

才可以被其他线程锁定。

·read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以

便随后的load动作使用。

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

变量副本中。

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

拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。

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

每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。

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

后的write操作使用。

·write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的

变量中。

具体过程:

​​​​​​​

以上就是JMM 定义的 8 种操作,JVM 在实现时必须保证每种操作都是原子的。

JMM 三大特性

原子性

        JMM 保证来直接保证的原子操作是read、load、use、assign、store、write这六个,也就是说,对于基本数据类型的访问、读写都是原子性的。如果我们需要保证一个更大范围的原子性保证,JMM 还提供了 lock、unlock原子操作,只不过JVM 并没有把这两个操作直接开放给用户使用,但是却提供了更高级别的字节码指令monitorenter和monitorexit来隐式的使用这两个操作,在Java代码层面就是synchronized关键字。

        可见性和有序性都是由volatile关键字来保证的,而volatile又是通过内存屏障来实现的,对于增加了volatile关键字修饰的共享变量,JVM虚拟机会自动插入内存屏障,而内存屏障底层是通过汇编lock指令来实现的

lock汇编指令作用(也就是内存屏障的作用):

  1. 会将当前处理器缓存行的数据立即写回到系统内存(保证了可见性)
  2. 这个写回内存的操作会引起在在其他CPU里缓存了该内存地址的数据无效(MESI协议)
  3. 提供内存屏障功能,使lock前后指令不能重排序(保证了有序性)

 Java规范定义的内存屏障

可见性

        当JVM 发现变量被volatile修饰,volatile变量的修改需要及时的回写到主内存(lock汇编指令的作用),回写到主内存时要通过总线来进行传输,这时就可以借助MESI缓存一致性协议通过总线嗅探来监控其他所有线程的工作内存中拥有该变量的缓存行,将该缓存行失效,当其他线程再次使用该变量时就需要访问主内存中的最新数据,从而实现可见性。 

有序性

        导致出现有序性问题是因为JVM 通过指令重排序对代码进行优化可能导致多线程下出现问题。volatile 是如何实现的呢?通过内存屏障(lock汇编指令的作用)。

Java规定的volatile需要实现的内存屏障

在 “volatile写操作” 之前加入StoreStore屏障保证 “volatile写操作” 之前的变量的读操作不会和 “volatile写操作” 之后的读操作发生重排序,其他类似。 

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

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

相关文章

牛客网刷题-(1)

🌈write in front🌈 🧸大家好,我是Aileen🧸.希望你看完之后,能对你有所帮助,不足请指正!共同学习交流. 🆔本文由Aileen_0v0🧸 原创 CSDN首发🐒 如…

[C++] C++入门

☃️个人主页:fighting小泽 🌸作者简介:目前正在学习C和Linux 🌼博客专栏:C入门 🏵️欢迎关注:评论👊🏻点赞👍🏻留言💪🏻 …

Git基本命令和使用

文章目录 1、Git本地库命令1.1、初始化本地库1.2、设置用户签名1.3、查看本地库状态1.4、将工作区的修改添加到暂存区1.5、将暂存区的修改提交到本地库1.6、历史版本1.7、取消commit1.8、取消暂存文件 2、分支操作2.1、查看分支2.2、创建分支2.3、分支合并时产生冲突 3、Gitee远…

交换机端口灯常亮 端口up状态 服务器设置ip交换机获取不到服务器网卡mac地址 不能通信

环境: 深信服防火墙 8.0.75 AF-2000-FH2130B-SC S6520X-24ST-SI交换机 version 7.1.070, Release 6530P02 问题描述: 交换机一个vlan下有3台服务器,连接端口2、3、4,2和3连接的服务器正常,交换机3端口灯常亮 端口up状态 服务器自动获取不了地址,改为手动设置ip后,交…

跳跃游戏Ⅱ-----题解报告

题目:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 与Ⅰ不同的是,这次要求找出最小的跳跃次数。思路也很简单,在每一次跳跃之后都更新最远的跳跃距离。 举个列子: 输入:2,3,1,1,4 第一次…

Scrapy设置代理IP方法(超详细)

Scrapy是一个灵活且功能强大的网络爬虫框架,用于快速、高效地提取数据和爬取网页。在某些情况下,我们可能需要使用代理IP来应对网站的反爬机制、突破地理限制或保护爬虫的隐私。下面将介绍在Scrapy中设置代理IP的方法,以帮助您更好地应对这些…

javaEE - 1(9000字详解多线程)

一:认识线程 1.1 线程的概念 线程是操作系统中执行的最小单位,它是进程中的一个实体。一个进程可以包含多个线程,并且这些线程共享进程的资源,如内存、文件句柄等,但每个线程有自己的独立执行流程和栈空间。 线程在…

完整搭建Git服务器

文章目录 搭建Git服务器第一步,安装git:第二步,创建一个git用户,用来运行git服务第三步,添加SSH公钥第四步,初始化Git仓库:第五步,连接Git服务器 搭建Git服务器 GitHub就是一个免费…

【PyTorch】深度学习实践 02 线性模型

深度学习的准备过程 准备数据集选择模型模型训练进行推理预测 问题 对某种产品花费 x 个工时,即可得到 y 收益,现有 x 和 y 的对应表格如下: x (hours) y(points)12243648 求花费4个工时可得…

【Dockerfile镜像实战】构建LNMP环境并运行Wordpress网站平台

这里写目录标题 一、项目背景和要求二、项目环境三、部署过程1)创建自定义网络2)部署NginxStep1 创建工作目录并上传相关软件包Step2 编写Dockerfile文件Step3 编写配置文件nginx.confStep4 创建nginx镜像Step5 运行容器 3)部署MysqlStep1 创…

selenium多窗口、多iframe切换、alert、3种等待

1、多标签/多窗口之间的切换 场景: 在页面操作过程中有时候点击某个链接会弹出新的窗口,这时就需要切换到新打开的窗口上进行操作。这种情况下,需要识别多标签或窗口的情况。 操作方法: switch_to.window()方法:切换…

《数据结构与算法之美》读书笔记1

Java的学习 方法参数多态(向上和向下转型) 向上转型: class Text{public static void main(String[] args) {Animals people1 new NiuMa();people1.eat1();//调用继承后公共部分的方法,没重写调用没重写的,重写了调…