当前位置: 首页 > news >正文

Java内存模型(Java Memory Model,JMM)

​        JMM​​ 是Java虚拟机(JVM)规范中定义的一组规则和规范,用于描述多线程环境下,Java程序中变量的访问和修改行为,尤其是在并发编程中如何保证内存可见性原子性有序性。JMM 是 Java 并发编程的基石,它定义了线程之间如何通过内存进行交互,确保程序在不同平台和处理器架构上具有一致的并发行为。(JMM保证了java并发编程的跨平台)


一、JMM 的核心目标

JMM 的主要目标是解决多线程环境下的三个核心问题:

  1. ​原子性(Atomicity)​:​保证某些操作是不可分割的,要么全部执行,要么全部不执行,不会被其他线程干扰。

  2. ​可见性(Visibility)​:​当一个线程修改了共享变量的值后,其他线程能够立即看到这个修改。

  3. ​有序性(Ordering)​:​程序执行的顺序按照代码的先后顺序执行,避免指令重排序导致的逻辑错误。


二、JMM 的基本概念

1. 主内存与工作内存(重点)

JMM 抽象了线程与主内存之间的关系:

  • ​主内存(Main Memory)​​:所有线程共享的内存区域,存储所有的实例变量、静态变量等。可以类比为计算机中的物理内存。

  • ​工作内存(Working Memory)​​:每个线程都有自己的工作内存(类似于CPU的寄存器或缓存),线程从主内存中读取变量到自己的工作内存中进行操作,操作完成后再将结果写回主内存。工作内存是线程私有的,线程之间不能直接访问彼此的工作内存。

2. 内存间的交互操作(不是重点)

JMM 定义了八种原子操作,用于线程与主内存之间的交互:

  1. ​lock(锁定)​​:作用于主内存的变量,将一个变量标识为一条线程独占的状态。
  2. ​unlock(解锁)​​:作用于主内存的变量,释放一个变量的锁定状态。
  3. ​read(读取)​​:作用于主内存的变量,将一个变量的值从主内存传输到线程的工作内存,以便随后的load操作。
  4. ​load(载入)​​:作用于工作内存的变量,将read操作得到的值放入工作内存的变量副本中。
  5. ​use(使用)​​:作用于工作内存的变量,将工作内存中的一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用变量的字节码指令时就会执行这个操作。
  6. ​assign(赋值)​​:作用于工作内存的变量,将执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
  7. ​store(存储)​​:作用于工作内存的变量,将工作内存中的一个变量的值传送到主内存中,以便随后的write操作。
  8. ​write(写入)​​:作用于主内存的变量,将store操作得到的值放入主内存的变量中。

这些操作必须按特定的规则组合执行,以确保内存操作的原子性、可见性和有序性。


三、JMM 与 Java 并发编程的关系

        JMM 为 Java 并发编程提供了一套规范,确保在多线程环境下程序的行为是可预测和一致的。它通过定义内存屏障(Memory Barriers)、happens-before 关系等机制,来控制线程间的内存可见性和操作顺序。

1. Happens-Before 原则

​Happens-Before​​ 是 JMM 中的一个核心概念,用于判断两个操作之间的执行顺序。如果操作A happens-before 操作B,那么操作A的结果对操作B可见,并且操作A在操作B之前执行。

JMM 定义了以下几种 Happens-Before 关系:

  1. ​程序次序规则(Program Order Rule)​
    在同一个线程中,按照程序代码的顺序,前面的操作 happens-before 后面的操作。

  2. ​锁定规则(Monitor Lock Rule)​
    一个线程解锁操作 happens-before 另一个线程对同一个锁的加锁操作。

  3. ​volatile 变量规则(Volatile Variable Rule)​
    对一个 volatile 变量的写操作 happens-before 后续对这个变量的读操作。

  4. ​线程启动规则(Thread Start Rule)​
    Thread 对象的 start() 方法调用 happens-before 启动线程中的任何操作。

  5. ​线程终止规则(Thread Termination Rule)​
    线程中的任何操作 happens-before 其他线程检测到该线程已经终止(通过 Thread.join() 方法或 Thread.isAlive() 返回 false)。

  6. ​线程中断规则(Thread Interruption Rule)​
    对线程 interrupt() 方法的调用 happens-before 被中断线程检测到中断事件(通过 Thread.interrupted() 或 Thread.isInterrupted())。

  7. ​对象终结规则(Finalizer Rule)​
    一个对象的初始化完成 happens-before 它的 finalize() 方法的开始。

  8. ​传递性(Transitivity)​
    如果操作A happens-before 操作B,且操作B happens-before 操作C,那么操作A happens-before 操作C。

​        Happens-Before原则帮助开发者理解和推断多线程程序中的内存可见性和操作顺序,从而编写出正确且高效的并发代码。

2. 内存屏障(Memory Barriers)

        虽然 JMM 在规范层面定义了 Happens-Before 关系,但在实际实现中,JVM 会通过插入​​内存屏障​​来保证这些关系。内存屏障是一种硬件或软件机制,用于控制指令的执行顺序和内存访问的顺序,防止指令重排序和保证内存可见性。

常见的 memory barriers 包括:

屏障类型作用说明
​LoadLoad 屏障​确保 Load1 的数据加载先于 Load2 及后续的加载操作防止 Load2 读取到比 Load1 更旧的数据
​StoreStore 屏障​确保 Store1 的数据存储先于 Store2 及后续的存储操作防止 Store2 覆盖 Store1 的数据
​LoadStore 屏障​确保 Load1 的数据加载先于 Store2 及后续的存储操作防止 Store2 存储的数据比 Load1 读取的数据更旧
​StoreLoad 屏障​确保 Store1 的数据存储先于 Load2 及后续的加载操作防止 Load2 读取到比 Store1 更旧的数据(最耗性能)

        这些屏障在不同的处理器架构上有不同的实现方式,JVM 会根据目标平台插入相应的屏障指令,以保证 JMM 的语义。


四、JMM 与 Java 关键字的关系

        Java 提供了一些关键字和工具来帮助开发者控制内存可见性和线程同步,这些机制在底层依赖于 JMM 的规范。

1. volatile关键字

2. synchronized关键字​

http://www.dtcms.com/a/311725.html

相关文章:

  • 关于鸦片战争的历史
  • Dify 上次文件大小突破15MB,解决办法?
  • Store / Slice / Reducer
  • 麦肯锡咨询公司PEI经典面试题目汇总
  • Python编程基础与实践:Python循环结构基础
  • 洛谷 P3870 [TJOI2009] 开关-普及+/提高
  • 音视频学习(四十四):音频处理流程
  • 第三章 用户和权限
  • 线程池的实现
  • SQL Server从入门到项目实践(超值版)读书笔记 22
  • 内网穿透系列十:高性能内网穿透工具 rathole,支持Docker一键部署
  • 什么是DOM和BOM?
  • 机器学习-KNN
  • springboot大学生成绩管理系统设计与实现
  • Git 的基本使用指南(1)
  • 人类学家与建筑师:区分UX研究和项目管理的需求分析
  • TFS-2022《A Novel Data-Driven Approach to Autonomous Fuzzy Clustering》
  • LVGL代码框架简介
  • 从底层架构到多元场景:计算机构成与应用的深度剖析
  • Mac电脑安装HomeBrew
  • 从AI智能体出发,重构数据中台:迈向Agentic时代的数据能力体系
  • 微积分基础 | 核心概念 / 公式推导
  • 【51单片机6位数码管密码锁】2022-10-15
  • 入门MicroPython+ESP32:安装逗脑IDE及驱动
  • 深入 Go 底层原理(十一):Go 的反射(Reflection)机制
  • ESP32 外设控制基础:GPIO 应用详解与输入输出案例
  • Text2SQL:如何通过自然语言直接获取数据,打破技术壁垒?
  • ventoy 是一个非常棒的开源工具,可以制作多系统的usb启动盘
  • Allegro降版本工具
  • Python 全局解释器锁