从头开始学习->JVM(一):java内存模型(JMM)不是java虚拟机内存模型(JVM)哦!

1,897 阅读7分钟

《从头开始学习JVM》系列文章:

《从头开始学习->JVM(前言)》

《从头开始学习->JVM(前言)——拖更的理由?》

《从头开始学习->JVM(一):java内存模型(JMM)不是java虚拟机内存模型(JVM)哦!》

《从头开始学习->JVM(二):为什么java需要JVM(Java虚拟机)?》

《从头开始学习->JVM(三):类加载器(上)》

《从头开始学习->JVM(四):类加载器(中)》

《从头开始学习->JVM(五):类加载器(下)【源码分析】》

《从头开始学习->JVM(六):线程和JVM的关系》

《从头开始学习->JVM(七):运行时数据区(上)》

《从头开始学习->JVM(八):运行时数据区(下)》

《从头开始学习->JVM(九):垃圾收集(上)》

《从头开始学习->JVM(十):垃圾收集(中)》

《从头开始学习->JVM(十一):垃圾收集(下)》

前言

在进入jvm的世界之前,我要先给大家整理一个概念上的细节,java内存模型和jvm内存模型,是两回事哦。

在网上很多朋友的博客上,都会无意识的将java内存模型和jvm内存模型混为一谈,这让一部分不明白真相的看客都会以为是这样,但是实际上java内存模型和jvm内存模型,在概念上来讲是两回事,当然,不能否认的是这两者有着极大的关联性,甚至某种意义上来讲,JVM是JMM的实现方式,JMM是为JVM服务的,但是不能因为这样,就把两者混为一谈哦。(主要就是因为JMM是为多线程服务的,而JVM中也有为多线程服务的概念内容)

那么如果我们要了解JVM,那么我们势必要对JMM要一定的了解。当然,JMM本身也是一个非常复杂的概念,如果想要真正的了解它,不是我在文章中简单的说几句,就能深入理解的,但是现在,我们只是简单的去了解一下JMM,见识一下它,方便后面我们对JVM的理解。

那么,java内存模型 ( JMM ),到底是什么呢?

在去了解 JMM 之前,我们得先知道,为什么java虚拟机规范要定义 JMM 呢?

一. JMM(java内存模型)的缘来

在java中,有一个非常重要的特性,我相信这个特性,所有学过java的人都知道,这个特性就是我们经常挂在嘴边的:多线程编程

多线程编程的过程中,会有多个线程的出现,那么在多个线程出现的并发编程中,我们需要处理两个关键问题:

1.线程之间如何通信
2.线程之间如何同步(这里的线程是指并发执行的活动实体)。

在这里,我们先不展开讨论,我们只集中在第一点,那就是线程之间如何通信。(这里讲的通信是指线程之间以何种机制来交换信息)

而在命令式编程中,线程之间的通信机制有两种:

1.共享内存
  线程之间共享程序的公共状态,线程之间通过写-读内 存中的公共状态来隐式进行通信。
2.消息传递。 
  在消息传递的并发模型里,线程之间没有公共状 态,线程之间必须通过明确的发送消息来显式进行通信。 

而在我们主要关注的java这种命令式编程中,采用的就是共享内存的模式,而Java线程之间的通信总是隐式进行,整个通信过程对程序员完全透明。如果编写多线程程序的Java程序员不理解隐式进行的线程之间通信的工作机制,很可能会遇到各种奇怪的内存可见性问题。

而这就引申出来一个问题,那就是在共享内存这种模式中,java的线程之间的隐式通讯,是由什么控制的呢?

没错,控制java线程之间的隐式通讯的,正是我们本文要讲的,java内存模型JMM。

二. 为什么java需要JMM?

理论上讲,在计算机发展到今天的时候,我们在实际的物理机上,已经有合适的内存模型了,而且我们也有很多其他的选择方案,那么为什么java最终还是选择了创造属于自己的内存模型呢?当然,由于java是最早的尝试提供内存模型的语言,我们可以说,为什么java一开始就执着于创造属于自己的内存模型呢?

在这里,我们必须要说到java的一个经典理论:“一次开发,到处执行”。

在实现这个能力的过程中,java发现,问题的难度是被低估了,因为没有缜密的内存模型定义,存在很多模棱两可的地方,比如说对不同的处理器硬件,不同的操作系统之间,有的支持缓存一致性,有的不支持,都有各自的内存排序模型,而java自己又没有规定内存模型的话,那么这个时候,java所谓的“一次开发,到处执行”肯定就无法实现了。

PS : 缓存不一致,两个线程对内存的读/写操作,没有一个统一的规范规定,最后会导致内存中最终计算后的数据,和我们希望的数据不一致。

说白了,JMM的主要目标是定义程序中各个变量的访问规则,也就是在虚拟机中将变量存储到内存以及从内存中取出变量(这里的变量,指的是共享变量,也就是实例对象、静态字段、数组对象等存储在堆内存中的变量。而对于局部变量这类的,属于线程私有,不会被共享)这类的底层细节。通过这些规则来规范对内存的读写操作,从而保证指令执行的正确性。

所以,java迫切的需要一个完善的内存模型,能够让所有的java开发者,所有的不同平台的编译器,所有的JVM工程师们,能够清楚明白的达成一致。

于是,java内存模型JMM就诞生了。

三 JMM做了什么?

在前面我说过了,java中,线程之间的通信是由JMM控制的。JMM决定一个线程对共享变量的写入何时对另一个线程可见。

JMM规定,线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是一个JMM定义的一个概念,并不是真实存在的,本地内存涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。

线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。

不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行。

而JMM就作用于工作内存和主存之间数据同步过程。他规定了如何做数据同步以及什么时候做数据同步。

java内存模型JMM的抽象示意图如下:

结束语

本文主要是因为在我决定写一个JVM相关的系列文章后,在网上查阅资料的时候,经常发现很多技术博客的博主,会把java内存模型和JVM弄混淆,也许很多技术大佬是知道这两者的不同,只是在写文章的时候,没有特地的去避讳这两者的区别,导致了我这样的小萌新的懵逼。

JVM是java虚拟机模型,而JMM是java内存模型,可以说是完全不同的,而且JMM中的主内存和工作内存,与JVM中的堆,栈,方法区也不是一个层次的划分,这两者基本上是没有关系的。

但是,从这两者中,我们可以学习到一个对系统的概念的划分思想,这也是对我们很有好处的。

因此,我将这篇文章,当做我JVM系列文章的第一篇。

参考书籍

程晓明:《深入理解Java内存模型》

参考博客

juejin.cn/post/684490…

blog.csdn.net/zhaomengszu…

blog.csdn.net/fuzhongmin0…

www.jianshu.com/p/8a58d8335…