【Java多线程学习7】JMM(Java内存模型)学习

这篇具有很好参考价值的文章主要介绍了【Java多线程学习7】JMM(Java内存模型)学习。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

JMM(Java内存模型)学习

一、什么是Java内存模型? 为什么需要JMM?

JMM(Java内存模型),可以看作是Java定义的并发编程相关的一组规范,除了抽象了线程和主内存之间的关系之外,其还规定了从Java源代码CPU可执行指令的这个转化过程中要遵守哪些并发相关的原则和规范,其主要目的是简化多线程编程增强程序的可移植性

至于为什么需要JMM呢?为什么需要遵循这些并发相关的原则和规范呢,这是因为并发编程下,像 CPU 多级缓存指令重排这类设计可能会导致程序运行出现一些问题。就需要定义一些规范来解决这些问题,开发者可以利用这些规范更方便地开发多线程程序,保证程序的安全可靠。

二、CPU缓存 及 指令重排序 会带来什么问题呢?

(一)CPU Cache

我们知道,CPU Cache 缓存的是内存数据用于解决 CPU 处理速度和内存不匹配的问题(CPU的处理速度要远远高于内存的处理速度)。
CPU Cache 的工作方式: 先复制一份数据到 CPU Cache 中,当 CPU 需要用到的时候就可以直接从 CPU Cache 中读取数据,当运算完成后,再将运算得到的数据写回 Main Memory 中。但是,这样存在 内存缓存不一致性的问题 !比如我执行一个 i++ 操作的话,如果两个线程同时执行的话,假设两个线程从 CPU Cache 中读取的 i=1,两个线程做了 i++ 运算完之后再写回 Main Memory 之后 i=2,而正确结果应该是 i=3。
CPU 为了解决内存缓存不一致性问题可以通过制定缓存一致协议。

(二)指令重排序

什么是指令重排序呢? 简单来说就是系统在执行代码的时候并不一定是按照你写的代码的顺序依次执行。举个例子:
object = new SingleObject();这段代码其实分为三步执行:

  • 1、为object分配内存空间。
  • 2、初始化object对象。
  • 3、将object指向分配的内存地址。

但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1->3->2。指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T1 执行了 1 和 3,此时 T2 调用 getSingleObject()后发现 object不为空,因此返回 object,但此时 object还未被初始化。

那如何防止指令重排序的产生呢?
对于处理器,通过插入内存屏障(Memory Barrier,或有时叫做内存栅栏,Memory Fence)的方式来禁止特定类型的处理器重排序。
内存屏障(Memory Barrier,或有时叫做内存栅栏,Memory Fence)是一种 CPU 指令,用来禁止处理器指令发生重排序(像屏障一样),从而保障指令执行的有序性。另外,为了达到屏障的效果,它也会使处理器写入、读取值之前,将主内存的值写入高速缓存,清空无效队列,从而保障变量的可见性。

三、JMM如何抽象线程和主内存之间的关系?

Java 内存模型(JMM) 抽象了线程和主内存之间的关系,就比如说线程之间的共享变量必须存储在主内存中。

什么是主内存?什么是本地内存?

  • 主内存:所有线程创建的实例对象都存放在主内存中,不管该实例对象是成员变量还是方法中的本地变量(也称局部变量)
  • 本地内存:每个线程都有一个私有的本地内存来存储共享变量的副本,并且,每个线程只能访问自己的本地内存,无法访问其他线程的本地内存。本地内存是JMM 抽象出来的一个概念,存储了主内存中的共享变量副本。

【Java多线程学习7】JMM(Java内存模型)学习,java,学习,开发语言
从上图来看,线程 1 与线程 2 之间如果要进行通信的话,必须要经历下面 2 个步骤:

  • 线程 1 把本地内存中修改过的共享变量副本的值同步到主内存中去。
  • 线程 2 到主存中读取对应的共享变量的值。

也就是说,JMM 为共享变量提供了可见性的保障。文章来源地址https://www.toymoban.com/news/detail-679889.html

到了这里,关于【Java多线程学习7】JMM(Java内存模型)学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java 内存模型(JMM)探寻原理,深度讲解

    目录 一. 前言 二. 为什么会有内存模型 2.1. 硬件内存架构 2.2. 缓存一致性问题 2.3. 处理器优化和指令重排序 三. 并发编程的问题 四. Java 内存模型(JMM) 4.1. Java 运行时内存区域与硬件内存的关系 4.2. Java 线程与主内存的关系 4.3. 线程间通信 五. 主内存和工作内存 六. J

    2024年04月22日
    浏览(34)
  • Java内存模型(JMM)和volatile原理

    目录 一、Java 内存模型 二、可见性 三、有序性 四、volatile原理  1、可见性保证 2、有序性保证 五、线程安全的单例 JMM即Java Memory Model,他定义了 主存(共享的数据) 、 工作内存(私有的数据) 抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等 JMM体现以下

    2024年02月09日
    浏览(42)
  • Java内存区域(运行时数据区域)和内存模型(JMM)

    Java 内存区域和内存模型是不一样的东西,内存区域是指 Jvm 运行时将数据分区域存储,强调对内存空间的划分。 而内存模型(Java Memory Model,简称 JMM )是定义了线程和主内存之间的抽象关系,即 JMM 定义了 JVM 在计算机内存(RAM)中的工作方式,如果我们要想深入了解Java并发

    2024年02月12日
    浏览(44)
  • 区分什么是Java内存模型(JMM)和 JVM运行时数据区

    Java的内存区域和内存模型是不一样的东西,内存区域是指 JVM 运行时将数据分区域存储,强调对内存空间的划分 。 而内存模型(Java Memory Model,简称 JMM )是 定义了线程和主内存之间的抽象关系,即 JMM 定义了 JVM 在计算机内存(RAM)中的工作方式 ,如果我们要想深入了解Java并

    2024年02月11日
    浏览(48)
  • 【javaEE面试题(五)在JMM(Java Memory Model (Java 内存模型))下谈volatile的作用】

    volatile 能保证内存可见性 volatile 修饰的变量, 能够保证 “内存可见性”. 代码在写入 volatile 修饰的变量的时候 改变线程工作内存中volatile变量副本的值 将改变后的副本的值从工作内存 刷新到主内存 代码在读取 volatile 修饰的变量的时候 从主内存中读取volatile变量的最新值到

    2024年02月13日
    浏览(43)
  • 【javaEE面试题(五)在JMM(Java Memory Model (Java 内存模型))下谈volatile的作用】【保证内存可见 和 指令有序】

    volatile 能保证内存可见性 volatile 修饰的变量, 能够保证 “内存可见性”. 代码在写入 volatile 修饰的变量的时候 改变线程工作内存中volatile变量副本的值 将改变后的副本的值从工作内存 刷新到主内存 代码在读取 volatile 修饰的变量的时候 从主内存中读取volatile变量的最新值到

    2024年02月16日
    浏览(36)
  • 第十二章 Java内存模型与线程(二)

    12.4.1 线程的实现 实现线程主要有三种方式:使用 内核线程实现(1: 1 实现) ,使用 用户线程实现(1: N 实现 ),使用 用户线程加轻量级进程混合实现(N: M 实现) 。 1.内核线程实现 ​ 使用内核线程 实现的方式也被称为 1: 1 实现 。内核线程(Kernel-Level Thread,KLT)就

    2024年01月16日
    浏览(50)
  • 并发编程之三大特性及JMM内存模型

    目录 原子性 如何保证原子性 可见性 如何保证可见性 有序性 如何保证有序性 Java内存模型(JMM内存模型) Java内存模型的一些关键概念: 主内存与工作内存交互协议 Java内存模型通过以下手段来确保多线程程序的正确性: 锁机制 volatile volatile禁止指令重排序  Happens-Before 并发三

    2024年01月19日
    浏览(41)
  • 【JUC系列-01】深入理解JMM内存模型的底层实现原理

    JUC系列整体栏目 内容 链接地址 【一】深入理解JMM内存模型的底层实现原理 https://zhenghuisheng.blog.csdn.net/article/details/132400429 【二】深入理解CAS底层原理和基本使用 https://blog.csdn.net/zhenghuishengq/article/details/132478786 【三】熟练掌握Atomic原子系列基本使用 https://blog.csdn.net/zhenghuis

    2024年02月12日
    浏览(44)
  • Java/Python/Go不同开发语言在进程、线程和协程的设计差异

    在多线程项目开发时,最常用、最常遇到的问题是 1,线程、协程安全 2,线程、协程间的通信和控制 本文主要探讨不同开发语言go、java、python在进程、线程和协程上的设计和开发方式的异同。 进程 进程是 操作系统进行资源分配的基本单位,每个进程都有自己的独立内存空

    2024年01月23日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包