原创 一文读懂Java内存模型(JMM)及volatile关键字

发布时间:2021-08-02 10:28:16 浏览 934 来源:猿笔记 作者:一角钱技术

    而Java内存模型中规定所有变量都存储在主内存,但线程对变量的操作(读取赋值等)必须在工作内存中进行,工作内存是每个线程的私有数据区域。所有线程创建的实例对象都存放在主内存中,主要存储当前方法的所有本地变量信息(工作内存中存储着主内存中的变量副本拷贝),它们也会在各自的工作内存中创建属于当前线程的本地变量,注意由于工作内存是每个线程的私有数据,因此存储在工作内存的数据不存在线程安全问题。根据JVM虚拟机规范主内存与工作内存的数据存储类型以及操作方式。而对象实例将存储在主内存(共享数据区域,至于static变量以及类本身相关信息将会存储在主内存中。


    #主题列表:juejin,github,smartblue,cyanosis,channing-cyan

    #投稿主题:

    theme:cyanosis

    highlight:vs2015

    ##前言

    -并发编程从对操作系统底层工作的整体理解开始](

    在前一篇文章中,我们从操作系统底层的整个工作中,学习了一些硬件和操作系统层面的并发编程知识。在这篇文章中,我们继续学习一些在采访中必须要问的关于JMM模型和Volatile关键字的知识点。

    ##什么是JMM模型?

    JavaMemoryModel(简称JMM)是一个抽象的概念,并不真正存在。它描述了一组规则或规范,通过这些规则或规范定义了程序中各种变量(包括实例字段、静态字段和构成数组对象的元素)的访问模式。JVM运行程序的实体是线程,每创建一个线程,JVM都会创建一个工作内存(有些地方叫栈空间),用来存储线程的私有数据。但是Java内存模型规定所有变量都存储在主存中,主存是一个共享内存区域,所有线程都可以访问,但是线程对变量的操作(比如读取和赋值)必须在工作内存中进行。首先,我们需要测试从主内存到增加的工作内存空间的变量,然后对变量进行操作。操作完成后,我们不能直接操作主存中的变量。工作内存将变量的副本存储在主存中,主存是每个线程的私有数据区,因此不同线程不能访问彼此的工作内存,线程之间的通信(值传递)必须通过主存完成。

    ###JMM不同于JVM内存区域模式

    JMM和JVM之间的内存区域划分在不同的概念层次上。更恰当地说,JMM描述了一组规则,这些规则控制共享数据区和私有数据区中各种变量的访问模式。**JMM专注于原子性、秩序和可见性。JMM和Java内存区唯一的相似之处就是有共享数据区和私有数据区。在JMM,主存属于共享数据区,在一定程度上应该包括堆和方法区,而工作内存数据线程的私有数据区在一定程度上应该包括程序计数器、虚拟机栈和本地方法栈。

    线程、工作内存和主内存的工作交互图(基于JMM规范),如下:

    # # #主存储器

    Java实例对象主要是存储的,线程创建的所有实例对象都存储在主存中,不管* *实例对象是方法中的成员变量还是局部变量(也称为局部变量),还包括共享类信息、常量和静态变量。因为它是一个共享数据区,所以多个线程访问同一个变量可能会导致线程安全问题。

    # # #工作记忆

    它主要存储当前方法的所有局部变量信息(主内存中变量的副本存储在工作内存中),每个线程只能访问自己的工作内存,即线程中的局部变量对其他线程不可见。即使两个线程执行同一段代码,它们也会在自己的工作内存中创建属于当前线程的局部变量,包括字节码行号指示符和相关的Native方法信息。请注意,由于工作内存是每个线程的私有数据,线程之间无法相互访问工作内存,因此工作内存中存储的数据不存在线程安全问题。

    根据JVM虚拟机指定的主存和工作内存的数据存储类型和操作方式,对于一个实例对象中的一个成员方法,如果方法中包含的局部变量是基本数据类型(boolean、type、short、char、int、long、float、double),那么直接存储在工作内存的帧栈中,而对象实例则存储在主存(共享数据区、堆)中。但是,实例对象的成员变量,无论是基本数据类型还是包装类型(Integer、Double等)。)或引用类型,将存储在堆区域中。至于静态变量和类本身的相关信息,会存储在主存中。

    需要注意的是,主存中的实例对象可以被多个线程共享。如果两个线程同时调用同一个对象的同一个方法,那么两个线程会将待操作数据的一个副本复制到直接工作内存中,然后执行后期操作后刷新到主存。该模型如下图所示:

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

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

作者信息

一角钱技术 [等级:3] Java架构师
发布了 162 篇专栏 · 获得点赞 1171 · 获得阅读 60154

相关推荐 更多