返回顶部
首页 > 资讯 > 后端开发 > Python >Java内存模型的深入讲解
  • 140
分享到

Java内存模型的深入讲解

2024-04-02 19:04:59 140人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录内存模型硬件架构Java内存模型与硬件关联对象的可见性竞争条件总结Java内存模型展示了Java虚拟机是如何与计算机内存交互的,解决多线程读写共享内存时资源访问的问题。 内存模型

Java内存模型展示了Java虚拟机是如何与计算机内存交互的,解决多线程读写共享内存时资源访问的问题。

内存模型

Java虚拟机中的内存模型将线程栈与堆划分开,下图描述了Java内存模型的逻辑图。

每个线程都要自己的线程栈,栈中存储着线程执行到当前位置所调用的方法信息,线程执行代码时,线程栈会不断执行入栈和出栈操作。

线程栈中会存储所有被调用的方法中定义的变量,并且自己访问自己栈中的变量,别的线程不可见。即使两个线程执行相同的代码,也会在线程自己的栈中重复创建变量。一个线程可能会传递变量副本给另一个线程,但不能共享变量本身。

在栈中变量存储形式也有所不同。属于基本变量类型(int,byte,long,boolean,char,double,float,short)的变量,会直接将变量值存储在栈中,而其余类型的变量的值被存储在堆中,线程栈中只保留指向堆中变量地址的指针。
堆中则存储Java程序中创建的所有对象,不管是什么线程创建的。创建对象并将其分配给局部变量,或者将其创建为另一个对象的成员变量都没有影响,该对象仍存储在堆中。

值得注意的是,Java中的静态类变量也会随着类初始化而存储在堆中。

有指向对象指针的所有线程都可以访问堆上的对象。当线程可以访问对象时,它也可以访问该对象的成员变量。如果两个线程同时在同一个对象上调用一个方法,则它们都将有权访问该对象的成员变量,但是每个线程将拥有自己的局部变量副本。

两个线程有一组局部变量,指向堆上的共享对象。这两个线程分别具有对同一对象的不同指针。它们的指针也是局部变量,因此存储在每个线程的线程栈中(在每个线程上)。但是,两个不同的指针指向堆上的同一对象。
下面的代码块就是上图的一个实际例子。


public class MyRunnable implements Runnable() {

    public void run() {
        methodOne();
    }

    public void methodOne() {
        int localVariable1 = 45;
        MySharedObject localVariable2 = MySharedObject.sharedInstance;
        //...
        methodTwo();
    }

    public void methodTwo() {
        Integer localVariable1 = new Integer(99);
        //...
    }
}

public class MySharedObject {

    //static variable pointing to instance of MySharedObject
    public static final MySharedObject sharedInstance = new MySharedObject();

    //member variables pointing to two objects on the heap
    public Integer object2 = new Integer(22);
    public Integer object4 = new Integer(44);

    public long member1 = 12345;
    public long member2 = 67890;
}

硬件架构

现代硬件的内存架构与Java内存模型还是有些不同的,了解硬件架构对理解Java内存模型也有帮助。简单的硬件架构图如下:

现代计算机一般是多核CPU,一般不止一个CPU,因此多个线程是可能在物理意义上并发运行的。这意味着,如果Java应用程序是多线程的,则每个CPU可能在Java应用程序中同时(并发)运行一个线程。

每个CPU包含一组寄存器,这些寄存器本质上是CPU内存储器。CPU在这些寄存器上执行操作的速度比对主存储器中的变量执行操作的速度快得多,这是因为CPU可以比访问主存储器更快地访问这些寄存器。

每个CPU可能还具有一个CPU高速缓存。实际上,大多数现代CPU都有一定大小的高速缓存。CPU可以比其主存储器更快地访问其高速缓存,但是通常不如其访问其内部寄存器的速度快。因此,CPU高速缓存存储器位于内部寄存器和主存储器之间的速度之间。某些CPU可能具有多个高速缓存层(L1和L2 Cache)。了解Java内存模型如何与内存交互并不是很重要,重要的是要知道CPU可以具有某种高速缓存层。

计算机还包含一个主存储区(RAM)。所有CPU都可以访问主存储器。主存储区通常比CPU的高速缓存大得多。

通常,当CPU需要访问主内存时,它将部分主内存读入其CPU缓存中。它甚至可以将缓存的一部分读入其内部寄存器,然后对其执行操作。当CPU需要将结果写回主存储器时,它将把值从其内部寄存器刷新到高速缓存,然后在某个时候将值刷新回主存储器。

当CPU需要将其他内容存储在高速缓存中时,通常会将高速缓存中存储的值刷新回主存储器。CPU高速缓存可以一次将数据写入其部分内存,并一次刷新其部分内存。它不必每次更新都读取/写入完整的缓存。通常,缓存在称为“缓存行”的较小存储块中更新,可以将一个或多个高速缓存行读入高速缓存存储器,并且可以将一个或多个高速缓存行再次刷新回主存储器。

Java内存模型与硬件关联

如前所述,Java内存模型和硬件内存体系结构是不同的,硬件内存体系结构不能区分线程堆栈和堆。在硬件上,线程堆栈和堆都位于主内存中。线程堆栈和堆的某些部分有时可能会出现在CPU缓存和内部CPU寄存器中。下图对此进行了说明:

当对象和变量可以存储在计算机的各种不同存储区域中时,可能会出现某些问题。 两个主要问题是:

  • 线程更新(写入)到共享变量的可见性。
  • 读取,检查和写入共享变量时的竞争条件。

对象的可见性

如果两个或多个线程共享一个对象,而没有正确使用volatile关键字,则一个线程对共享对象进行的更新可能对其他线程不可见。

每个线程都可以拥有自己的共享库副本,每个副本位于不同的CPU缓存中。想象一下,共享对象最初存储在主存储器中。然后,在CPU上运行的一个线程将共享对象读入其CPU缓存并进行修改。只要未将CPU缓存刷新回主存储器,在其他CPU上运行的线程就看不到共享对象的更改版本。

下图说明了这种情况,在左CPU上运行的一个线程将共享对象复制到其CPU缓存中,并将其count变量更改为2。在右CPU上运行的其他线程看不到此更改,因为尚未将count更新写回主内存。

当然这个问题可以使用volatile关键字来解决。

竞争条件

如果两个或多个线程共享一个对象,并且一个以上的线程更新该共享对象中的变量,则可能会发生竞争条件。

假如线程A将共享对象的变量count读入其CPU缓存中,而线程B执行同样操作,但是它位于不同的CPU缓存中。现在,线程A加一个要计数,线程B也执行相同的操作。现在count已增加两次,在每个CPU高速缓存中增加一次。

如果这些增加是顺序执行的,则变量计数将增加两次,并将原始值+2写回到主存储器中。

但是,这两个增量是在没有同步的情况下并发执行的。不管线程A和B中哪个线程将其更新后的版本写回主内存,尽管有两个增量,但更新后的值仅比原始值高1。

该图说明了如上所述的竞争条件问题的发生:

这个问题可以使用synchronized关键字来解决。

总结

到此这篇关于Java内存模型的文章就介绍到这了,更多相关Java内存模型内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java内存模型的深入讲解

本文链接: https://lsjlt.com/news/129864.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java内存模型的深入讲解
    目录内存模型硬件架构Java内存模型与硬件关联对象的可见性竞争条件总结Java内存模型展示了Java虚拟机是如何与计算机内存交互的,解决多线程读写共享内存时资源访问的问题。 内存模型...
    99+
    2024-04-02
  • 深入了解volatile和Java内存模型
    目录前言为什么我们需要volatile?保证数据的可见性禁止指令重排序Java内存模型(JMM)JMM下的内存逻辑结构内存交互的操作重排序Volatile实现原理禁止重排序实现原理可...
    99+
    2022-11-13
    Java内存模型 Java volatile Java 内存模型 volatile
  • 怎么深入理解Java内存模型JMM
    这期内容当中小编将会给大家带来有关怎么深入理解Java内存模型JMM,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java 内存模型Java 内存模型(JMM)是一种抽象的概念,并不真实存在,它描述了一组...
    99+
    2023-06-05
  • 深入了解Java虚拟机栈以及内存模型
    目录1、结合字节码指令理解Java虚拟机栈和栈帧2、深入分析2.1 栈指向堆2.2 方法区指向堆2.3 堆指向方法区2.4 Java对象内存布局3、内存模型 3.1 图解3...
    99+
    2024-04-02
  • Java 内存模型进阶:深入理解 happens-before 关系
    一、happens-before 关系的基础 happens-before 关系是 JMM 定义的一种偏序关系,它规定了线程之间内存操作的顺序,确保了线程安全和并发编程的正确性。happens-before 关系主要分为以下几类: 程...
    99+
    2024-02-04
    Java 内存模型 happens-before 关系 线程安全 并发编程
  • GoLang内存模型详细讲解
    目录栈内存-协程栈-调用栈逃逸分析go 堆内存堆如何进行分配go 语言对象的垃圾回收如何减少GC对性能的分析GC 优化效率栈内存-协程栈-调用栈 为什么go的栈是在堆上? go 协程...
    99+
    2022-12-15
    GoLang内存模型 Go内存模型
  • C/C++深入讲解内存管理
    目录C/C++内存分布C语言中的动态内存管理C++的内存管理operator new与operator delete函数operator new与operator dele...
    99+
    2024-04-02
  • 详解Java的内存模型
    目录JVM的内存模型Java “一次运行,到处编译” 的真面目JVM的本质和位置JVM的内存模型总览线程私有区域线程共享区域直接内存从例子来理解内存模型JVM的内存模型 Java “...
    99+
    2024-04-02
  • C++泛型模板约束深入讲解
    CPP参考:(新标准) 传送门 模板对于类型的约束: 约束 template_get_size 泛型T只允许接受类型:list<T>,其实为 C/C++ 泛型模板例化特性...
    99+
    2024-04-02
  • Python万字深入内存管理讲解
    目录Python内存管理一、对象池1.小整数池2.大整数池3.inter机制(短字符串池)二、垃圾回收2.1.引用计数2.1.1 引用计数增加2.1.2 引用计数减少2.2.标记清除...
    99+
    2024-04-02
  • Java——内存模型详解!
    Java内存模型是一种抽象的规则或规范,定义了程序中存在竞争现象的对象(包括实例字段、静态字段和数组对象,不包括局部变量,形式参数;后者是线程私有,不存在竞争问题)的访问方式。         如果我们要想深入了解Java并发编程,就要先理...
    99+
    2023-10-20
    java 开发语言
  • Java内存模型详解
    目录什么是JMM主存与工作内存volatile 关键字有什么用一个线程对共享变量做了修改之后,其他的线程能够看到(感知到)该变量的这种修改(变化)什么是JMM JMM全称Java M...
    99+
    2023-05-18
    Java内存模型 Java JMM模型
  • Java运行时数据区域(内存划分)的深入讲解
    1. 程序计数器(线程私有) 程序计数器是一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器(切换线程后,能恢复到正确的执行位置). 2. Java虚拟机栈(线程私...
    99+
    2024-04-02
  • C#内存管理CLR深入讲解(上篇)
    半年之前,PM让我在部门内部进行一次关于“内存泄露”的专题分享,我为此准备了一份PPT。今天无意中将其翻出来,觉得里面提到的关于CLR下关于内存管理部分的内存...
    99+
    2024-04-02
  • C#内存管理CLR深入讲解(下篇)
    《上篇》中我们主要讨论的是程序集(Assembly)和应用程序域(AppDomain)的话题,着重介绍了两个不同的程序集加载方式——独占方式和共享方式(中立域...
    99+
    2024-04-02
  • Java深入浅出讲解代理模式
    目录1、动态代理模式2、JDK动态代理3、JDK动态代理代码演示1、动态代理模式 动态代理的特点: 当代理对象的时候,不需要实现接口代理对象的生成,是利用JDK的API,动态的在内存...
    99+
    2024-04-02
  • Java内存模型JMM详解
    Java Memory Model简称JMM, 是一系列的Java虚拟机平台对开发者提供的多线程环境下的内存可见性、是否可以重排序等问题的无关具体平台的统一的保证。(可能在术语上与Java运行时内存分布有歧义,后者指堆、方法区、线程栈等内存...
    99+
    2023-05-30
    java 内存模型 详解
  • JAVA内存模型(JMM)详解
    目录前言JAVA并发三大特性可见性有序性原子性Java内存模型真面目Happens-Before规则1.程序的顺序性规则2. volatile 变量规则3.传递性锁的规则5.线程 s...
    99+
    2022-12-08
    JAVA 内存模型 java内存模型和jvm内存模型的区别 java jmm模型
  • Java内存区域与内存模型详解
    这篇文章主要介绍“Java内存区域与内存模型详解”,在日常操作中,相信很多人在Java内存区域与内存模型详解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java内存区域与内存模型详解”的疑惑有所帮助!接下来...
    99+
    2023-06-02
  • C语言深入讲解内存操作问题
    目录一、野指针二、野指针的由来三、基本原则四、小结-上 五、常见的内存错误六、内存操作的规则七、小结-下 一、野指针 指针变量中的值是非法的内存地址,进而形成野指...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作