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

简介: Java内存模型(Java Memory Model,JMM)


今天简单聊聊什么叫做 Java 内存模型,不是 JVM 内存结构哦。

JMM 是一个语言级别的内存模型,处理器的硬件模型是硬件级别,Java中的内存模型是内存可见性的基本保证。从而为我们 volatile 实现内存可见性提供了基石。主要目的就是让 Java 程序员在各种平台下达到一致性访问效果

JMM决定一个线程对共享变量的写入何时对另一个线程可见,尤其是在对共享变量的读写,修改后其他线程立刻内读取到,这个就是JMM主要作用。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化。Java内存模型的抽象示意如图所示。

image.png

前面我们说到 volatile 底层原理详解,这个语义的实现就是利用了Java的内存模型。为我们屏蔽了细节,实现了内存可见性,有兴趣的读者可以看公众号前期发的文章 volatile 底层原理实现

为什么需要JMM?

1. 从源代码到指令序列的重排序

在执行程序的时候,为了提高性能,编译器与处理器常会对指令进行重排序优化,保证执行结果与书序执行的结果是一致的,但并不能保证各个语句执行的先后顺序与输入的代码顺序一致。(当然是说在单线程的情况下)。

所以有 volatile 修饰的代码就不会被指令重排,相当于加了一道内存屏障,不能把后面的指令重排序到内存屏障之前。

2. Happens-before原则(先行发生)

Happens-before定义:

  • 如果一个操作 Happens-before 另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序在第二个操作之前。
  • 两个操作之间存在 Happens-before 关系,并不意味着必须按照代码指定顺序执行。如果重排序后的执行结果与按照 Happens-before 结果执行的结果一致,那也是可以的。

先行发生是 Java 内存模型中定义的两项操作之间的偏序关系,如果说操作A先行发生于B,其实就是说在发生操作 B 之前,操作 A 产生的影响能被 B 观察到, “影响” 包括修改了内存中共享变量的值、发送了消息、调用了方法。比如:

//在线程 A 执行  1
i =  2;`
// 在线程 B 执行   2
j = i;`
// 在线程 C 执行   3
i =  3;
  • 假设执行顺序是 1 -> 3 -> 2:那么 j 的值是 3。
  • 假设执行顺序是 1 -> 2 -> 3:那么 j 的值是 2。

若我们想要按照 1 ,2 ,3顺序执行。那么只有同步才能保证一致性。

总而言之:

  • 通过JMM内存模型,volatile 内存可见性的实现才得以保证。但是又不需要我们去关注不同平台的细节。当对一个 volatile 修饰的变量修改是,JMM 会把该线程对应的本地内存中的共享变量刷新到主内存中。
  • 当读一个 volatile 变量的时候, JMM 会把该线程对应的本地内存设置无效,并从主内存中读取共享变量。
  • volatile 在满足 Happens-before原则情况下,禁止指令重排序。
相关文章
|
11月前
|
Java 大数据 Go
从混沌到秩序:Java共享内存模型如何通过显式约束驯服并发?
并发编程旨在混乱中建立秩序。本文对比Java共享内存模型与Golang消息传递模型,剖析显式同步与隐式因果的哲学差异,揭示happens-before等机制如何保障内存可见性与数据一致性,展现两大范式的深层分野。(238字)
393 4
|
11月前
|
存储 缓存 Java
【深入浅出】揭秘Java内存模型(JMM):并发编程的基石
本文深入解析Java内存模型(JMM),揭示synchronized与volatile的底层原理,剖析主内存与工作内存、可见性、有序性等核心概念,助你理解并发编程三大难题及Happens-Before、内存屏障等解决方案,掌握多线程编程基石。
|
12月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
1277 3
|
缓存 监控 Kubernetes
Java虚拟机内存溢出(Java Heap Space)问题处理方案
综上所述, 解决Java Heap Space溢出需从多角度综合施策; 包括但不限于配置调整、代码审查与优化以及系统设计层面改进; 同样也不能忽视运行期监控与预警设置之重要性; 及早发现潜在风险点并采取相应补救手段至关重要.
1130 17
|
存储 监控 算法
Java垃圾回收机制(GC)与内存模型
本文主要讲述JVM的内存模型和基本调优机制。
|
11月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
550 1
|
11月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
484 1
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
514 0
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
671 16