java并发编程(二十二)——初识Java内存模型

本文探讨了Java内存模型(JMM)的重要性和作用,解释了从Java代码到CPU指令的执行过程,强调了JMM为解决处理器和JVM差异带来的不一致性问题而设立的标准。同时,区分了JVM内存结构与Java内存模型的区别,前者关注运行时数据区域,后者关注并发编程。JMM涵盖了重排序、原子性和内存可见性三大关键点,确保多线程编程的可预测性。文章还介绍了JVM内存结构的六大区域,如堆、虚拟机栈、方法区等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

前面我们学习了一些并发的基础知识,常见的并发工具的使用,但是我们仅仅是停留在使用的阶段,要想了解Java并发的底层原理,要知其所以然,还得更进一步学习一些Java内存模型的知识。本文我们来深入研究下与Java并发息息相关的Java内存模型的相关知识。

从Java代码到CPU指令

我们都知道,编写的 Java 代码,最终还是要转化为 CPU 指令才能执行的。为了理解 Java 内存模型的作用,我们首先就来回顾一下从 Java 代码到最终执行的 CPU 指令的大致流程:

  1. 最开始,我们编写的 Java 代码,是 *.java 文件;

  2. 在编译(包含词法分析、语义分析等步骤)后,在刚才的 .java 文件之外,会多出一个新的 Java 字节码文件(.class);

  3. JVM 会分析刚才生成的字节码文件(*.class),并根据平台等因素,把字节码文件转化为具体平台上的机器指令;

  4. 机器指令则可以直接在 CPU 上运行,也就是最终的程序执行。

为什么需要 JMM(Java Memory Model,Java 内存模型)?

在更早期的语言中,其实是不存在内存模型的概念的。

所以程序最终执行的效果会依赖于具体的处理器,而不同的处理器的规则又不一样,不同的处理器之间可能差异很大,因此同样的一段代码,可能在处理器 A 上运行正常,而在处理器 B 上运行的结果却不一致。同理,在没有 JMM 之前,不同的 JVM 的实现,也会带来不一样的“翻译”结果。

所以 Java 非常需要一个标准,来让 Java 开发者、编译器工程师和 JVM 工程师能够达成一致。达成一致后,我们就可以很清楚的知道什么样的代码最终可以达到什么样的运行效果,让多线程运行结果可以预期,这个标准就是 JMM,这就是需要 JMM 的原因。

JVM 内存结构 VS Java 内存模型

Java 作为一种面向对象的语言,有很多概念,从名称上看起来比较相似,比如 JVM 内存结构、Java 内存模型,这是两个截然不同的概念,但是很容易混淆。网络上也有不少讲 Java 内存模型的文章,其实写的是 JVM 内存结构。

我们就先从整体上概括一下这两者的主要作用:

JVM 内存结构和 Java 虚拟机的运行时区域有关

Java 内存模型和 Java 的并发编程有关

可以看出,这两个概念其实是有很大区别的。下面我们先来简要介绍一下 JVM 内存结构。

JVM 内存结构

我们都知道,Java 代码是要运行在虚拟机上的,而虚拟机在执行 Java 程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途。在《Java 虚拟机规范(Java SE 8)》中描述了 JVM 运行时内存区域结构可分为以下 6 个区。

堆区(Heap):堆是存储类实例数组的,通常是内存中最大的一块。实例很好理解,比如 new Object() 就会生成一个实例;而数组也是保存在堆上面的,因为在 Java 中,数组也是对象。

虚拟机栈(Java Virtual Machine Stacks):它保存局部变量和部分结果,并在方法调用和返回中起作用。

方法区(Method Area):它存储每个类的结构,例如运行时的常量池、字段和方法数据,以及方法和构造函数的代码,包括用于类初始化以及接口初始化的特殊方法。

本地方法栈(Native Method Stacks):与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的 Java 方法服务,而本地方法栈则是为 Native 方法服务

程序计数器(The PC Register):是最小的一块内存区域,它的作用通常是保存当前正在执行的 JVM 指令地址

运行时常量池(Run-Time Constant Pool):是方法区的一部分,包含多种常量,范围从编译时已知的数字到必须在运行时解析的方法和字段引用。

注意,以上是 Java 虚拟机规范,不同的虚拟机实现会各有不同,一般会遵守规范。

总结一下,JVM 内存结构是由 Java 虚拟机规范定义的,描述的是在 Java 程序执行过程中,由 JVM 管理的不同数据区域,各个区域有其特定的功能。

Java 内存模型(JMM )是什么

JMM 是规范

MM 是和多线程相关的一组规范,需要各个 JVM 的实现来遵守 JMM 规范,以便于开发者可以利用这些规范,更方便地开发多线程程序。这样一来,即便同一个程序在不同的虚拟机上运行,得到的程序结果也是一致的。

如果没有 JMM 内存模型来规范,那么很可能在经过了不同 JVM 的“翻译”之后,导致在不同的虚拟机上运行的结果不一样,那是很大的问题。

因此,JMM 与处理器、缓存、并发、编译器有关。它解决了 CPU 多级缓存、处理器优化、指令重排等导致的结果不可预期的问题。

JMM 是工具类和关键字的原理

之前我们使用了各种同步工具和关键字,包括 volatile、synchronized、Lock 等,其实它们的原理都涉及 JMM。正是 JMM 的参与和帮忙,才让各个同步工具和关键字能够发挥作用,帮我们开发出并发安全的程序。

比如我们写了关键字 synchronized,JVM 就会在 JMM 的规则下,“翻译”出合适的指令,包括限制指令之间的顺序,以便在即使发生了重排序的情况下,也能保证必要的“可见性”,这样一来,不同的 JVM 对于相同的代码的执行结果就变得可预期了,我们 Java 程序员就只需要用同步工具和关键字就可以开发出正确的并发程序了,这都要感谢 JMM。

JMM 里最重要 3 点内容,分别是:重排序原子性内存可见性

总结

我们了解了什么是Java内存模型,与jvm内存结构的区别,回顾了jvm内存结构的相关知识,对JMM有了个大概的认识,JMM包含了重排序、原子性、内存可见性三方面最主要的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员资料站

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值