JAVA 内存模型(一)

简介:

综述:

 简单的说,Java的内存模型定义了在一个线程对一个共享变量进行修改后,修改后的共享变量什么时候对其它线程可见。

作用:

  1. 对于程序员

       JMM给程序员呈现出来的是具有顺序一致性的强内存模型。(通俗点就是所见即所得)
  2. 对于处理器与编译器

        JMM给处理器与编译器提供了一个比较弱的happens-before内存模型,这样尽可能多的给处理器与编译器优化代码的空间。
    

处理器与编译器的优化技术

  1. 编译器优化的重排序。

    编译器在不改变单线程程序语义的前提下,可以对我们编写的代码进行重排。如下:
    
public class Test { 
    public static void main(String args []) {
        int a = 1;       // 1
        int b = 2;      // 2
        // 在单线程语义下这个程序的输出为 1
        // 交换标注为 1,2 的两行代码不改变单线程程序语义
        // 编译器可以对这样的代码进行指令重排,以提高程序运行的性能
        System.out.println(a);
    }       
 }  
public class Test {
    public static void main(String args[ ]) {
        int a = 0;                          // 1
        a = 2;                              // 2
        a = 3;                              // 3
        // 在单线程语义下这个程序的输出为3
        // 如果标注为 2 ,3的代码进行交换顺序,那就改变了单线程语义,JMM
        // 是禁止这种重排序的。
        System.out.println(a);  
    }
}

2 . 处理器的指令级并行重排序

     现代处理器采用了指令级并行技术,来对多条指令进行重排序。如果指令间不存在数据依赖(<u>对同一个变量写后读,读后写,写后写</u>),那处理器就可以改变指令间的执行顺序。如下:
  0x00007f31c9108ac0: mov    %eax,-0x14000(%rsp)
  0x00007f31c9108ac7: push   %rbp
  0x00007f31c9108ac8: sub    $0x30,%rsp
  0x00007f31c9108acc: movabs $0x7f31c8c00448,%rdi  ;   {metadata(method data for {method} {0x00007f31c8c00260} 'test' '()V' in 'testTwo')}
  0x00007f31c9108ad6: mov    0xdc(%rdi),%ebx
  // 假设以上5条汇编指令之间不存在数据依赖,如果处理器的流水线大于等于5,那么,这5条汇编指令可以并行的进行计算。

3 . 内存系统的重排序

     由于处理器使用缓存,这使得加载和存储操作看上去是在乱序执行。如图[1]:

screenshot
intel i7 处理器是4核8线程,每个核心都有自己的L1, L2 缓存,当不同的核心缓存相同的共享变量,并写回到L3 缓存时,就存在内存系统的重排序。

Happens-before 规则

  综述:happens-before 关系是由Lamport(1978)这位大神提出的。它的表述为: a -> b 读作“a 在 b 之前发生”,意思是所有的进程(分布式系统中)/ 线(我们现在讨论的JMM)一致认为事件 a  先于事件 b 发生:*注意:这里的先发生实际上是一种可见性的表述,它并不代表在物理时间上事件a先于事件b发生,而是事件b在执行前要能看到事件a执行后的结果。*这就为处理器,与编译器的重排提供了保证。

我们来看看JSR-133对JMM中happens-before规则的示例:

1. 程序顺序规则:一个线程中的的每个操作,happens-before于该线程中的任意后续操作。
2. 监视器规则: 对一个锁的解锁,happens-before于随后对这个锁的加锁。
3. volatile变量规则:对一个volatile域的写,happens-before与任意后续对这个volatile域的读。
4. 传递性: 如果 a -> b, b -> c, 则 a -> c.
5. 线程启动 start() 规则:如果线程A 执行操作ThreadB.start()(启动线程B),那么A线程的启动线程的操作,happens-before于线程B中的任意操作。
6. join()规则: 如果线程A 执行ThreadB.join()并成功返回,那么线程B中的任意操作,happens-before 于线程A 从ThreadB.join()操作成功返回。

顺序一致性内存模型

综述:顺序一致性模型是一个被计算机科学家理想化了的理论参考模型,它为程序员提供了内存可见性的保证。
顺序一致性的两大特征:
1. 一个线程中所有操作必须按照程序的顺序来执行
2.不管程序是否同步,所有线程都只能看到一个单一的操作执行顺序。在顺序一致性内存模型中,每个操作都必须原子执行且对所有线程立即可见。

本博客是对《JAVA并发编程的艺术》方腾飞,魏鹏,程晓明 著。第三章的读后感。

参考资料:[1] intel开发技术手册卷3第2章

目录
相关文章
|
3月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
373 3
|
4月前
|
存储 缓存 Java
Java数组全解析:一维、多维与内存模型
本文深入解析Java数组的内存布局与操作技巧,涵盖一维及多维数组的声明、初始化、内存模型,以及数组常见陷阱和性能优化。通过图文结合的方式帮助开发者彻底理解数组本质,并提供Arrays工具类的实用方法与面试高频问题解析,助你掌握数组核心知识,避免常见错误。
|
2月前
|
Java 大数据 Go
从混沌到秩序:Java共享内存模型如何通过显式约束驯服并发?
并发编程旨在混乱中建立秩序。本文对比Java共享内存模型与Golang消息传递模型,剖析显式同步与隐式因果的哲学差异,揭示happens-before等机制如何保障内存可见性与数据一致性,展现两大范式的深层分野。(238字)
95 4
|
2月前
|
存储 缓存 Java
【深入浅出】揭秘Java内存模型(JMM):并发编程的基石
本文深入解析Java内存模型(JMM),揭示synchronized与volatile的底层原理,剖析主内存与工作内存、可见性、有序性等核心概念,助你理解并发编程三大难题及Happens-Before、内存屏障等解决方案,掌握多线程编程基石。
|
3月前
|
缓存 监控 Kubernetes
Java虚拟机内存溢出(Java Heap Space)问题处理方案
综上所述, 解决Java Heap Space溢出需从多角度综合施策; 包括但不限于配置调整、代码审查与优化以及系统设计层面改进; 同样也不能忽视运行期监控与预警设置之重要性; 及早发现潜在风险点并采取相应补救手段至关重要.
577 17
|
7月前
|
存储 缓存 Java
【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理
JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。
251 0
|
4月前
|
监控 Kubernetes Java
最新技术栈驱动的 Java 绿色计算与性能优化实操指南涵盖内存优化与能效提升实战技巧
本文介绍了基于Java 24+技术栈的绿色计算与性能优化实操指南。主要内容包括:1)JVM调优,如分代ZGC配置和结构化并发优化;2)代码级优化,包括向量API加速数据处理和零拷贝I/O;3)容器化环境优化,如K8s资源匹配和节能模式配置;4)监控分析工具使用。通过实践表明,这些优化能显著提升性能(响应时间降低40-60%)同时降低资源消耗(内存减少30-50%,CPU降低20-40%)和能耗(服务器功耗减少15-35%)。建议采用渐进式优化策略。
236 1
|
4月前
|
存储 监控 算法
Java垃圾回收机制(GC)与内存模型
本文主要讲述JVM的内存模型和基本调优机制。
|
5月前
|
SQL 缓存 安全
深度理解 Java 内存模型:从并发基石到实践应用
本文深入解析 Java 内存模型(JMM),涵盖其在并发编程中的核心作用与实践应用。内容包括 JMM 解决的可见性、原子性和有序性问题,线程与内存的交互机制,volatile、synchronized 和 happens-before 等关键机制的使用,以及在单例模式、线程通信等场景中的实战案例。同时,还介绍了常见并发 Bug 的排查与解决方案,帮助开发者写出高效、线程安全的 Java 程序。
278 0