我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java内存模型原理是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java内存模型原理是什么

这篇文章主要介绍“Java内存模型原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java内存模型原理是什么”文章能帮助大家解决问题。

内部原理

JVM 中试图定义一种 JMM 来屏蔽各种硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的内存访问效果。

JMM 的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量与 Java 编程中的变量有所区别,它包括了实例字段、静态字段和构成数组对象的元素,但不包括局部变量与方法参数,因为后者是线程私有的,不会被共享,自然就不会存在竞争问题。为了获得较好的执行效能,Java 内存模型并没有限制执行引擎使用处理器的特定寄存器或缓存来和主存进行交互,也没有限制即使编译器进行调整代码执行顺序这类优化措施。

JMM 是围绕着在并发过程中如何处理原子性、可见性和有序性这 3 个特征来建立的。

JMM 是通过各种操作来定义的,包括对变量的读写操作,监视器的加锁和释放操作,以及线程的启动和合并操作。

内存模型结构

Java 内存模型把 Java 虚拟机内部划分为线程栈和堆。

线程栈

每一个运行在 Java 虚拟机里的线程都拥有自己的线程栈。这个线程栈包含了这个线程调用的方法当前执行点相关的信息。一个线程仅能访问自己的线程栈。一个线程创建的本地变量对其它线程不可见,仅自己可见。即使两个线程执行同样的代码,这两个线程任然在在自己的线程栈中的代码来创建本地变量。因此,每个线程拥有每个本地变量的独有版本。

所有原始类型的本地变量都存放在线程栈上,因此对其它线程不可见。一个线程可能向另一个线程传递一个原始类型变量的拷贝,但是它不能共享这个原始类型变量自身。

堆上包含在 Java 程序中创建的所有对象,无论是哪一个对象创建的。这包括原始类型的对象版本。如果一个对象被创建然后赋值给一个局部变量,或者用来作为另一个对象的成员变量,这个对象任然是存放在堆上。

  • 一个本地变量可能是原始类型,在这种情况下,它总是在线程栈上。

  • 一个本地变量也可能是指向一个对象的一个引用。在这种情况下,引用(这个本地变量)存放在线程栈上,但是对象本身存放在堆上。

  • 一个对象可能包含方法,这些方法可能包含本地变量。这些本地变量任然存放在线程栈上,即使这些方法所属的对象存放在堆上。

  • 一个对象的成员变量可能随着这个对象自身存放在堆上。不管这个成员变量是原始类型还是引用类型。

  • 静态成员变量跟随着类定义一起也存放在堆上。

  • 存放在堆上的对象可以被所有持有对这个对象引用的线程访问。当一个线程可以访问一个对象时,它也可以访问这个对象的成员变量。如果两个线程同时调用同一个对象上的同一个方法,它们将会都访问这个对象的成员变量,但是每一个线程都拥有这个本地变量的私有拷贝。

Java内存模型原理是什么

硬件内存架构

现代硬件内存模型与 Java 内存模型有一些不同。理解内存模型架构以及 Java 内存模型如何与它协同工作也是非常重要的。这部分描述了通用的硬件内存架构,下面的部分将会描述 Java 内存是如何与它“联手”工作的。

Java内存模型原理是什么

一个现代计算机通常由两个或者多个 CPU。其中一些 CPU 还有多核。从这一点可以看出,在一个有两个或者多个 CPU 的现代计算机上同时运行多个线程是可能的。每个 CPU 在某一时刻运行一个线程是没有问题的。这意味着,如果你的 Java 程序是多线程的,在你的 Java 程序中每个 CPU 上一个线程可能同时(并发)执行。

每个 CPU 都包含一系列的寄存器,它们是 CPU 内内存的基础。CPU 在寄存器上执行操作的速度远大于在主存上执行的速度。这是因为 CPU 访问寄存器的速度远大于主存。

每个 CPU 可能还有一个 CPU 缓存层。实际上,绝大多数的现代 CPU 都有一定大小的缓存层。CPU 访问缓存层的速度快于访问主存的速度,但通常比访问内部寄存器的速度还要慢一点。一些 CPU 还有多层缓存,但这些对理解 Java 内存模型如何和内存交互不是那么重要。只要知道 CPU 中可以有一个缓存层就可以了。

一个计算机还包含一个主存。所有的 CPU 都可以访问主存。主存通常比 CPU 中的缓存大得多。

通常情况下,当一个 CPU 需要读取主存时,它会将主存的部分读到 CPU 缓存中。它甚至可能将缓存中的部分内容读到它的内部寄存器中,然后在寄存器中执行操作。当 CPU 需要将结果写回到主存中去时,它会将内部寄存器的值刷新到缓存中,然后在某个时间点将值刷新回主存。

当 CPU 需要在缓存层存放一些东西的时候,存放在缓存中的内容通常会被刷新回主存。CPU 缓存可以在某一时刻将数据局部写到它的内存中,和在某一时刻局部刷新它的内存。它不会再某一时刻读/写整个缓存。通常,在一个被称作“cache lines”的更小的内存块中缓存被更新。一个或者多个缓存行可能被读到缓存,一个或者多个缓存行可能再被刷新回主存。

JMM 和硬件内存架构之间的桥接

上面已经提到,Java 内存模型与硬件内存架构之间存在差异。硬件内存架构没有区分线程栈和堆。对于硬件,所有的线程栈和堆都分布在主内中。部分线程栈和堆可能有时候会出现在 CPU 缓存中和 CPU 内部的寄存器中。如下图所示:

当对象和变量被存放在计算机中各种不同的内存区域中时,就可能会出现一些具体的问题。主要包括如下两个方面:

  • 线程对共享变量修改的可见性

  • 当读,写和检查共享变量时出现 race conditions

Java内存模型原理是什么

共享对象可见性

如果两个或者更多的线程在没有正确的使用 volatile 声明或者同步的情况下共享一个对象,一个线程更新这个共享对象可能对其它线程来说是不接见的。

想象一下,共享对象被初始化在主存中。跑在 CPU 上的一个线程将这个共享对象读到 CPU 缓存中。然后修改了这个对象。只要 CPU 缓存没有被刷新会主存,对象修改后的版本对跑在其它 CPU 上的线程都是不可见的。这种方式可能导致每个线程拥有这个共享对象的私有拷贝,每个拷贝停留在不同的 CPU 缓存中。

上图示意了这种情形。跑在左边 CPU 的线程拷贝这个共享对象到它的 CPU 缓存中,然后将 count 变量的值修改为 2。这个修改对跑在右边 CPU 上的其它线程是不可见的,因为修改后的 count 的值还没有被刷新回主存中去。

解决这个问题你可以使用 Java 中的 volatile 关键字。volatile 关键字可以保证直接从主存中读取一个变量,如果这个变量被修改后,总是会被写回到主存中去。

竞态条件

如果两个或者更多的线程共享一个对象,多个线程在这个共享对象上更新变量,就有可能发生 race conditions。

想象一下,如果线程 A 读一个共享对象的变量 count 到它的 CPU 缓存中。再想象一下,线程 B 也做了同样的事情,但是往一个不同的 CPU 缓存中。现在线程 A 将 count 加 1,线程 B 也做了同样的事情。现在 count 已经被增在了两个,每个 CPU 缓存中一次。

如果这些增加操作被顺序的执行,变量 count 应该被增加两次,然后原值+2 被写回到主存中去。

然而,两次增加都是在没有适当的同步下并发执行的。无论是线程 A 还是线程 B 将 count 修改后的版本写回到主存中取,修改后的值仅会被原值大 1,尽管增加了两次。

解决这个问题可以使用 Java 同步块。一个同步块可以保证在同一时刻仅有一个线程可以进入代码的临界区。同步块还可以保证代码块中所有被访问的变量将会从主存中读入,当线程退出同步代码块时,所有被更新的变量都会被刷新回主存中去,不管这个变量是否被声明为 volatile。

Happens-Before

JMM 为程序中所有的操作定义了一个偏序关系,称之为 Happens-Before。

  • 程序顺序规则:如果程序中操作 A 在操作 B 之前,那么在线程中操作 A 将在操作 B 之前执行。

  • 监视器锁规则:在监视器锁上的解锁操作必须在同一个监视器锁上的加锁操作之前执行。

  • volatile 变量规则:对 volatile 变量的写入操作必须在对该变量的读操作之前执行。

  • 线程启动规则:在线程上对 Thread.start 的调用必须在该线程中执行任何操作之前执行。

  • 线程结束规则:线程中的任何操作都必须在其他线程检测到该线程已经结束之前执行,或者从 Thread.join 中成功返回,或者在调用 Thread.isAlive 时返回 false。

  • 中断规则:当一个线程在另一个线程上调用 interrupt 时,必须在被中断线程检测到 interrupt 调用之前执行(通过抛出 InterruptException,或者调用 isInterrupted 和 interrupted)。

  • 终结器规则:对象的构造函数必须在启动该对象的终结器之前执行完成。

  • 传递性:如果操作 A 在操作 B 之前执行,并且操作 B 在操作 C 之前执行,那么操作 A 必须在操作 C 之前执行。

关于“Java内存模型原理是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网行业资讯频道,小编每天都会为大家更新不同的知识点。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java内存模型原理是什么

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java内存模型原理是什么

这篇文章主要介绍“Java内存模型原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java内存模型原理是什么”文章能帮助大家解决问题。内部原理JVM 中试图定义一种 JMM 来屏蔽各种硬件和
2023-06-02

Java内存模型的原理是什么

这篇文章将为大家详细讲解有关Java内存模型的原理是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。所有的编程语言中都有内存模型这个概念,区别于微架构的内存模型,高级语言的内存模型包括了编
2023-06-17

Java内存模型的原理以及其用法是什么

Java内存模型的原理以及其用法是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。为什么要有内存模型在介绍 Java 内存模型之前,我们先来看一下到底什么是计算机内存模型
2023-06-02

Java内存的原型及工作原理是什么

这篇文章给大家介绍Java内存的原型及工作原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。主要通过分析Java内存分配的栈、堆以以及常量池详细的讲解了其的工作原理。一、java虚拟机内存原型寄存器:我们在程序中
2023-06-17

Java的内存模型是什么

这篇文章主要介绍“Java的内存模型是什么”,在日常操作中,相信很多人在Java的内存模型是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java的内存模型是什么”的疑惑有所帮助!接下来,请跟着小编一起来
2023-06-15

Java内存模型volatile的内存语义是什么

这篇文章主要介绍“Java内存模型volatile的内存语义是什么”,在日常操作中,相信很多人在Java内存模型volatile的内存语义是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java内存模型v
2023-06-25

Java内存异常原理是什么

本篇内容主要讲解“Java内存异常原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java内存异常原理是什么”吧!1 . 对象的创建过程关于对象的创建,第一反应是new关键字,那么本文就
2023-06-02

Java内存模型的规定是什么

本篇内容介绍了“Java内存模型的规定是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!首先要明确内存模型指什么。书中的定义是:在特定的操
2023-06-02

Java内存模型的概念是什么

这篇文章主要介绍了Java内存模型的概念是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java内存模型的概念是什么文章都会有所收获,下面我们一起来看看吧。内存模型,英文名Memory Model,他是一个
2023-06-02

面试官:什么是Java内存模型?

Java 内存模型存在的原因在于解决多线程环境下并发执行时的内存可见性和一致性问题。在现代计算机系统中,尤其是多处理器架构下,每个处理器都有自己的高速缓存,而主内存(RAM)是所有处理器共享的数据存储区域。

Java内存分配原理是什么

本篇内容介绍了“Java内存分配原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!String常量池问题的几个例子下面是几个常见例子的
2023-06-17

java中内存模型的作用是什么

java中内存模型的作用是什么?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。java基本数据类型有哪些Java的基本数据类型分为:1、整数类型,用来表示整数的数据类型。2、
2023-06-14

Java8内存模型是什么

这篇文章主要介绍了Java8内存模型是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、JVM 内存模型根据 JVM 规范,JVM 内存共分为虚拟机栈、堆、方法区、程序计
2023-06-19

JMM内存模型是什么

这篇文章主要介绍“JMM内存模型是什么”,在日常操作中,相信很多人在JMM内存模型是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JMM内存模型是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!JM
2023-06-27

golang内存模型是什么

Golang的内存模型是一种并发内存模型,它定义了在不同Goroutine之间共享数据的行为。在Golang的内存模型中,每个Goroutine都拥有自己的栈,用于存储局部变量和函数调用信息。并且,每个Goroutine可以访问共享的堆内存
2023-10-20

什么是JVM内存模型?

本篇文章带大家初步了解一下JVM内存模型,有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。计算机内存模型在程序运行时,CPU通过访问主存获取数据,但随着CPU的快速发展,CPU访问速度越来越高,硬件无法满足CPU的条件下,大多内存加入了高速缓存
什么是JVM内存模型?
2016-08-29

Java内存模型包含什么

Java内存模型包含以下几个部分:1. 主内存(Main Memory):主内存是所有线程共享的内存区域,用于存储对象实例、静态变量和常量等数据。2. 工作内存(Working Memory):每个线程都有自己的工作内存,用于存储线程私有的
2023-08-24

Java 原型模式究竟是什么?(Java原型模式指的是什么)

在Java编程中,原型模式是一种创建对象的设计模式。它通过复制现有对象来创建新对象,而不是通过传统的构造函数来实例化对象。这种模式在某些情况下可以提高对象创建的效率,并且可以避免复杂的构造过程。一、原型模式的基本概念原型模式
Java 原型模式究竟是什么?(Java原型模式指的是什么)
Java2024-12-20

怎么理解Java内存模型

本篇内容主要讲解“怎么理解Java内存模型”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么理解Java内存模型”吧!内存模型的由来1. 计算机在执行程序的时候每条指令都是由CPU来执行的。而C
2023-06-16

面试官:说说什么是Java内存模型?

由于CPU 和主内存间存在数量级的速率差,想到了引入了多级高速缓存的传统硬件内存架构来解决,多级高速缓存作为 CPU 和主内间的缓冲提升了整体性能。解决了速率差的问题,却又带来了缓存一致性问题。

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录