当前位置:首页 > 内存 > 正文

Java 内存模型

  • 内存
  • 2024-06-10 16:48:47
  • 908

一、Java内存模型原理?

本文主要介绍模型产生问题的历史、它解决的问题、处理思路以及相应的实现规则,它们之间是紧密相关的。希望读者能够对Java内存模型体系有一个比较清晰的认识。通过阅读本文,了解它是什么以及为什么它是这样。

内存模型的历史

在介绍Java内存模型之前,Java课程参与者认为我们必须首先了解物理计算机的并行性问题。了解这些问题可以深入了解内存模型。

物理机面临的并发问题在很多方面与虚拟机遇到的并发问题相似。物理机的解决方案对于虚拟机的实现具有很大的参考价值。

物理机并发问题

硬件效率问题

计算机处理器无法仅依靠处理器的“计算”来处理当前的大多数任务。处理器至少要和内存进行交互,比如读取运算数据、存储运算结果等。这种I/O操作很难消除(单独使用寄存器不可能执行所有计算任务)。

由于计算机的存储设备和处理器的处理速度存在几个数量级的差距,为了避免处理器等待缓慢的内存完成读写操作,现代计算机系统最大限度地提高了存储设备的性能。缓存的读写速度接近处理器的速度。

缓存充当内存和处理器之间的缓冲区:将操作所需的数据复制到缓存中,以便可以快速执行操作。当操作完成时,它们会同步回来。高速缓存存储器。

缓存一致性问题

基于缓存的存储互操作性可以解决CPU和内存速度之间的紧张关系,但它也通过引入新问题而增加了计算机系统的复杂性。介绍:缓存一致性。

在多处理器系统(或单处理器、多核系统)中,每个处理器(每个核心)都有自己的缓存,并且它们共享相同的MainMemory。

当多个处理器的计算任务共享同一主存区域时,其对应的缓存数据可能会不一致。

为此,每个处理器在访问缓存时必须遵循一些协议,并在读写时按照协议进行操作,以保持缓存的一致性。



二、Java内存模型详解Java的内存模型:深入剖析与模型分析

在Java并发编程的世界里,通信和同步是核心要素。Java的内存模型主要基于共享内存。每个线程都有自己的私有本地内存,共享变量存储在主内存中。线程之间的通信由Java内存模型(JMM)精确控制,以便本地内存的更新能够及时正确地集成到主内存中,并且其他线程可以读取最新的状态。编译器和处理器的排序行为可能会给内存可见性带来挑战。


直观地理解,当线程A更新共享x变量时,这个变化会通过JMM从本地内存传输到主内存,然后线程B会读取更新后的值,基本上是如何内存模型有效。


排序现象分为编译器优化、安装级别的并行性、系统内存重新排序,这些都可以从乘法的细微问题中推导出来。JMM使用微妙的规则(例如StoreLoad屏障)来管理和防止导致问题的特定重新排列。例如,StoreLoad屏障确保全局内存访问顺序的一致性,即使在多处理器架构中也是如此。
内存模型的关键概念

JMM是一种抽象级语言,可确保跨平台内存可见性。进程内存重新排序可能会导致操作以与预期不同的顺序执行。现代处理器允许对Load缓存重新排序,但sparc-TSO和x86处理器有严格的限制。编译器通过插入内存缓冲区警告(例如LoadLoad、StoreStore、LoadStore和StoreLoad块)来保持一致性。


JSR-133提出了可见内存在操作之间定义的概念。这个概念并不强制操作按照特定的顺序执行,而是要求操作在后续操作之前是可见的。happens-before关系与JMM紧密结合,简化了理解内存重组的复杂性。已知三种类型的依赖关系,编译器和处理器遵循这些规则,以便简单程序的执行顺序保持不变。


重排序和多线程示例

在多线程编程中,线程B重新排序以删除共享变量值,尤其是在线程A更新之后。超级客户端可能会导致进程执行推测执行,这可能会导致意外的乘法结果。正如同步示例中所示,JMM确保正确同步的代码遵循一致性,即所有序列中的操作顺序都是一致的。


JMM通过互斥执行来限制关键部分的重新排序,从而允许执行编译器和处理器优化。对于未正确同步的程序,JMM提供基本的内存可见性保证,但不提供完全符合序列一致性模型。这些差异按处理机制可能导致的简单操作、原子长/双精度类型和非原子读写的顺序排列。


在内存可见性方面,例如计算电路的面积,JMM使得为所有涉及内存操作的序列提供一致的结果成为可能。JMM的简单概述如下:


在圆域中,在A->B、B->C关系发生之前对性能没有影响,JMM强调了这些关键已知记忆模型的关系
JMM区分了影响执行结果的重组和允许最好的重组。
Iconist设计强调其内存可见性保证的简单性以及对编译器和处理器的最小约束。

可见内存的强大之处在于,无论是单线程还是多线程,都能保证代码正确同步,保证执行的可靠性。同时,JMM针对不完全同步场景提供了基本的保护,这样问题就不会变得毫无用处。


最后,JSR-133引入的volatile和Final关键字增加了可见内存,保证了代码的正确性和初始化的安全性。总体而言,Java内存模型是一种平衡设计,旨在满足程序的编程需求,同时保持与编译器和处理器优化的兼容性。