首页 > 系统相关 >什么是Java内存模型(JMM)?

什么是Java内存模型(JMM)?

时间:2024-05-06 20:34:36浏览次数:15  
标签:Java 变量 线程 内存 JMM 操作

什么是Java内存模型(JMM)?

一、JMM的相关概念
Java内存模型简称JMM(Java Memory Model),是Java虚拟机所定义的一种抽象规范,用来屏蔽不同硬件和操作系统的内存访问差异,让java程序在各种平台下都能达到一致的内存访问效果。
这里要注意两点:
1)JMM是一个抽象的概念,并不是物理上的内存划分。
2)JMM-JVM-硬件的关系:Java内存模型(JMM)定义了Java虚拟机(JVM)在计算机内存(RAM)中的工作规范。在硬件内存模型中,各种CPU架构的实现是不尽相同的,Java作为跨平台的语言,为了屏蔽底层硬件差异,定义了Java内存模型(JMM)。JMM作用于JVM和底层硬件之间,屏蔽了下游不同硬件模型带来的差异,为上游开发者提供了统一的使用接口。
总之一句话:JMM是JVM的内存使用规范,是一个抽象的概念。

Java内存模型的抽象示意图:

如上图在JMM中,内存划分为两个区域,线程本地内存,主内存。

主内存:主内存被所有的线程所共享,所有的变量都存储在主内存中,包括实例变量,静态变量,但是不包括局部变量和方法参数
工作内存:线程的工作内存保存了该线程用到的变量和主内存的副本拷贝

线程对共享变量的所有操作都必须在工作内存进行,不能直接读写主内存中的变量。不同线程之间也无法访问彼此的工作内存,变量值的传递只能通过主内存来进行。


二、JMM定义了什么?
整个Java内存模型实际上是围绕着三个特征建立起来的。分别是:原子性,可见性,有序性。这三个特征可谓是整个Java并发的基础。

1. 原子性
原子性指的是一个操作是不可分割,不可中断的,一个线程在执行时不会被其他线程干扰。
实现方式:在 Java 中,可以借助synchronized、各种 Lock 以及各种原子类实现原子性。synchronized 和各种 Lock 可以保证任一时刻只有一个线程访问该代码块,因此可以保障原子性。各种原子类是利用 CAS (compare and swap)

2. 可见性
可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
实现方式:在 Java 中,可以借助synchronized、volatile 以及各种 Lock 实现可见性。
如果我们将变量声明为 volatile ,这就指示 JVM,这个变量是共享且不稳定的,每次使用它都到主内存中进行读取。
synchronized的原理是,在执行完,进入unlock之前,必须将共享变量同步到主内存中。

final修饰的字段,一旦初始化完成,如果没有对象逸出(指对象为初始化完成就可以被别的线程使用),那么对于其他线程都是可见的。

3. 有序性
有序性即程序执行的顺序按照代码的先后顺序执行。

说明:由于指令重排序问题,代码的执行顺序未必就是编写代码时候的顺序。指令重排序可以保证串行语义一致,但是没有义务保证多线程间的语义也一致 ,所以在多线程下,指令重排序可能会导致一些问题。
实现方式:在 Java 中,可以使用synchronized或者volatile保证多线程之间操作的有序性。
实现原理有些区别:

volatile关键字是使用内存屏障达到禁止指令重排序,以保证有序性。

synchronized的原理是,一个线程lock之后,必须unlock后,其他线程才可以重新lock,使得被synchronized包住的代码块在多线程之间是串行执行的。

三、八种内存交互操作
内存交互操作有8种:
lock(锁定):作用于主内存的变量,把一个变量标记为一个线程独占状态;
unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定;
read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便下一步的load操作使用;
load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中;
use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎;
assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量;
store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作;
wirte(写入):作用于工作内存的变量,它把store操作从工作内存中的一个变量值传送到主内存的变量中。

如果要把一个变量从主内存中复制到工作内存中,就需要按顺序地执行 read 和 load 操作;
如果把变量从工作内存中同步到主内存中,就需要按顺序地执行 store 和 write 操作。
但Java 内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行。

下面继续补充一下JMM对8种内存交互操作制定的规则:

1)不允许read、load、store、write操作之一单独出现,也就是read操作后必须load,store操作后必须write。
2)不允许线程丢弃他最近的assign操作,即工作内存中的变量数据改变了之后,必须告知主存。
3)不允许线程将没有assign的数据从工作内存同步到主内存。
4)一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是对变量实施use、store操作之前,必须经过load和assign操作。
5)一个变量同一时间只能有一个线程对其进行lock操作。多次lock之后,必须执行相同次数unlock才可以解锁。
6)如果对一个变量进行lock操作,会清空所有工作内存中此变量的值。在执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值。
7)如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量。
8)一个线程对一个变量进行unlock操作之前,必须先把此变量同步回主内存。


四、Java 内存区域和 JMM 有何区别?
这是一个比较常见的问题,很多初学者非常容易搞混。

Java 内存区域和内存模型是完全不一样的两个东西:JVM 内存区域和 Java 虚拟机的运行时区域相关,定义了 JVM 在运行时如何分区存储程序数据,就比如说堆主要用于存放对象实例。
Java 内存模型和 Java 的并发编程相关,抽象了线程和主内存之间的关系就比如说线程之间的共享变量必须存储在主内存中,规定了从 Java 源代码到 CPU 可执行指令的这个转化过程要遵守哪些和并发相关的原则和规范,其主要目的是为了简化多线程编程,增强程序可移植性的。

标签:Java,变量,线程,内存,JMM,操作
From: https://www.cnblogs.com/hld123/p/18175829

相关文章

  • 如何使用 JavaScript 获取当前页面帧率 FPS
    可以通过计算每秒 window.requestAnimationFrame 的调用频率来做为FPS值。它接收一个回调函数,该回调函数会在浏览器下一次重绘之前执行。所以只要我们循环调用并记录单位时间内的调用次数就能计算当前页面的帧率了。效果展示在线预览-使用JavaScript获取当前页面帧率FP......
  • Java中执行Shell命令
    Java中执行Shell命令Java执行Shell命令返回127引言在Java开发中,我们经常需要调用系统的Shell命令来完成一些特定的任务。然而,有时候执行Shell命令可能会返回一个特定的错误码,比如127。本文将介绍什么是Shell命令返回码,以及当Java执行Shell命令返回127时可能的原因和解决办法。......
  • Ubuntu 22.04.4 LTS 安装java
    记录一次Ubuntu22.04.4LTS安装java检查是否有自带安装jdkdpkg--list|grep-ijdk如果存在则卸载创建安装路径cd/usr/local/mkdirjavacdjava/解压java安装包tar-zxvf/home/to_install/jdk-8u281-linux-x64.tar.gz-C./解压完成后,/usr/local/java目录下......
  • ETL如何执行Java脚本
    ETLCloud提供了执行 Java 脚本的方式,让用户能够灵活地处理数据并实现各种复杂的数据处理任务。 ETLCloud在数据处理领域的应用优势主要体现在以下几个方面:灵活性:通过执行Java脚本,用户能够灵活定制数据处理逻辑,满足各种不同的业务需求。无论是简单的数据清洗还是复杂的数据......
  • top k 问题 Java解决代码
    topk问题:从10亿个数中选出最大的1万个数,处理方式:用小顶堆,先用1万个数建立小顶堆,再把剩余数从小顶堆里过一遍,每次与堆顶元素比较,小顶堆的堆顶元素是最小的,如果比堆顶元素大就替换堆顶元素,重新生成小顶堆,继续比较直到10亿条数据比完,堆里剩下的就是最大的1万个数。如果是从大量元素......
  • Java 集合框架的collection接口和map接口
    集合框架中整体的架构分为2类:Collection接口和Map接口Collection接口:用于存储单个对象的典型的实现类:List--->ArryListLinkedListSet--->HashSetThreeSetMap接口:用于存储K-V键值对双对象的典型的实现类:HashMap一、ArrayList1.1、简介数据存储:底层采用的是数组,但是采......
  • Java Web 相关
    页面静态页面:即静态网页,是实际存在的,无需经过服务器的编译,直接加载到客户浏览器上显示出来。静态页面需要占一定的服务器空间,且不能自主管理发布更新的页面,如果想更新网页内容,要通过FTP软件把文件DOWN下来用网页制作软件修改(通过fso等技术例外)。常见的静态页面举例:.html扩......
  • JavaGUI - [04] BoxLayout
    题记部分  一、简介  为了简化开发,Swing引入了一个新的布局管理器:BoxLayout。BoxLayout可以在垂直和水平两个方向上摆放GUI组件,BoxLayout提供了如下一个简单的构造器:BoxLayout(Containertarget,intaxis)  指定创建基于target容器的BoxLayout布局管理器,该布局管理......
  • Java Object类有那些方法,分别作用
    1.类构造器是创建Java对象的途径之一,通过new关键字调用构造器完成对象的实例化,或通过构造器对象进行相对应的初始化。在JDK的Object类源码中,系统会自动添加一个无参构造器。publicObject(){Objectobj=newObject();//构造一个Object类的对象}2.registerNatives......
  • Java面向对象编程概念
    面向对象编程(OOP)概念,如类、对象、继承、封装、多态概念:面向对象编程(Object-OrientedProgramming,简称OOP)是一种程序设计范型或编程范式。这种范式使用“对象”来设计应用程序和系统的各个部分。在面向对象编程中,万物皆对象,程序被视作一系列对象的集合,这些对象通过消息传递来交互......