别再问什么是Java内存模型了,看这里!

内存写入监视器 V2.0 内存写入监视器 V2.0 用于软件反编译 偷取别人补丁的一个好用根据 立即下载

别再问什么是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 之前执行。
内存写入监视器(驱动版)纯E 附驱动源码 内存写入监视器(驱动版)纯E 附驱动源码内存写入监视器(驱动版)纯E 附驱动源码内存写入监视器(驱动版)纯E 附驱动源码 立即下载

相关推荐

不用写触发器!帆软填报报表自动记录创建/修改时间的终极方案

本文详细介绍了帆软填报报表中无需编写数据库触发器,即可自动记录数据创建时间和修改时间的终极方案。该方案利用帆软内置函数和单元格条件属性,在应用层实现日期自动生成,有效规避了触发器带来的权限、维护和部署难题,为数据填报提供了更轻量、灵活且易于维护的解决方案。

weixin_28040125的博客 360

TensorFlow实战:从Eager Execution到SavedModel的工业级部署指南

在机器学习工程实践中,框架的部署便捷性与生产就绪性是决定项目成败的关键。计算图作为深度学习框架的核心抽象,通过将计算过程定义为数据流图,实现了高效的优化与跨平台执行。这种设计不仅提升了模型训练与推理的性能,更重要的是为工业级部署奠定了坚实基础。其技术价值在于能够将复杂的模型统一封装为标准格式,实现从研发到生产的无缝衔接。在实际应用场景中,这尤其体现在需要将模型部署到多样化终端(如移动设备、嵌入式系统或云端服务器)的复杂需求上。TensorFlow通过其SavedModel格式和丰富的工具链,如TensorF

weixin_30781433的博客 482

鸿蒙OpenHarmony南向开发 轻量系统芯片移植指南(一)

OpenHarmony系统采用"系统>子系统>部件"层级架构,支持功能模块化裁剪。本文介绍了关键子系统及移植方法:1)启动恢复子系统负责内核到应用间的进程初始化,需配置启动入口标识及链接脚本;2)文件子系统提供基础文件操作接口,需适配HAL层文件读写功能,可通过Flash模拟、轻量文件系统或厂商自有方案实现。移植过程需修改config.json配置,添加对应组件定义及功能实现。系统采用模块化设计,开发者可根据实际需求灵活配置所需子系统功能。

yx525623的博客 1131

聊聊Java内存模型(JMM)

它本身只是一个抽象的概念,并不真实存在,它描述的是一种规则或规范,是和多线程相关的一组规范。通过这组规范,定义了程序中对各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。需要每个JVM 的实现都要遵守这样的规范,有了JMM规范的保障,并发程序运行在不同的虚拟机上时,得到的程序结果才是安全可靠可信赖的。Java内存模型围绕着在并发过程中如何处理这三个特性而建立的模型。

qq_25409421的博客 3万+

【Python机器学习】零基础掌握TweedieRegressor广义线性回归模型

本次文章主要介绍了如何使用Tweedie回归模型预测电动汽车的实际续航里程。基于车速、气温和驾驶习惯等多种因素,模型能够准确地预测出电动汽车的续航里程,从而为生产商和消费者提供有用的信息。优点总结,Tweedie回归模型在处理具有多元性和高度散布的数据方面表现出色,特别适用于需要考虑多种影响因素的预测任务。优点名称对应描述说明多元性强可以同时处理多种类型和维度的数据高度可定制允许用户自定义损失函数和正则项对异常值鲁棒能够较好地处理数据中的异常值易于解释参数和预测结果都相对容易解释。

Mr数据杨 1006

pdb文件删除杂原子 HETATM;保留或去除水分子

这样操作水分子也会跟着删除,如果需要保留水分子。

weixin_42357472的博客 2645

终于有人把Java内存模型说清楚了

内部原理JVM 中试图定义一种 JMM 来屏蔽各种硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的内存访问效果。JMM 的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量与 Java 编程中的变量有所区别,它包括了实例字段、静态字段和构成数组对象的元素,但不包括局部变量与方法参数,因为后者是线程私有的,...

weixin_33717298的博客 467

数据库小技能:数据导入脚本

背景:版本大升级,从2.0升级到3.0 ,服务端开发语言从c#换到java语言。数据库类型从microsalft sql server 换到mysql。数据来源于微信,用于查询卡bin。

专注于计算机研发知识和资讯分享 774

如何设计一个多线程处理跑批功能

在分表、多机器、多线程跑批场景下,如何设计跑批功能,可以支持动态扩缩容机器、动态调整跑批线程、动态扩容表等功能

探索科技 脚踏实地 1158

【专栏必读】王道考研408计算机网络+湖科大教书匠计算机网络+网络编程万字笔记使用说明及章节导航

本文档汇总了王道考研408计算机网络和湖科大教书匠计算机网络课程的重点内容,包括计算机网络体系结构、物理层、数据链路层、网络层、传输层和应用层的详细讲解。通过ISO/OSI和TCP/IP模型,深入探讨了通信基础、介质访问控制、IP地址、TCP/UDP协议、流量控制和网络编程等关键概念。此外,还提供了Linux网络编程实践,帮助读者巩固理论知识

快乐江湖的博客 2万+

《派出你的AI同事:WorkBuddy案例实战》067:按行业分类的案例索引

按行业分类的案例索引 —— 《派出你的AI同事:WorkBuddy案例实战》系列文章,配图已统一为规范示意图。

LuckyHanMo的博客 99

终于有人把Java内存模型(JMM)说清楚了

前几天,发了一篇文章,介绍了一下JVM内存结构、Java内存模型以及Java对象模型之间的区别。有很多小伙伴反馈希望可以深入的讲解下每个知识点。Java内存模型,是这三个知识点当中最晦涩难懂的一个,而且涉及到很多背景知识和相关知识。 网上有很多关于Java内存模型的文章,在《深入理解Java虚拟机》和《Java并发编程的艺术》等书中也都有关于这个知识点的介绍。但是,很多人读完之后还是搞不清楚,甚至有的人说自己更懵了。本文,就来整体的介绍一下Java内存模型,目的很简单,让你读完本文以后,就知道到底Java

weixin_45380450的博客 220

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

别再问什么是Java内存模型了,看这里

网上有很多关于Java内存模型的文章,在《深入理解Java虚拟机》和《Java并发编程的艺术》等书中也都有关于这个知识点的介绍。但是,很多人读完之后还是搞不清楚,甚至有的人说自己更懵了。本文,就来整体的介绍一下Java内存模型,目的很简单,让你读完本文以后,就知道到底Java内存模型是什么,为什么要有Java内存模型,Java内存模型解决了什么问题等。本文中,有很多定义和说法,都是笔者自己理解后定义出来的。希望能够让读者可以对Java内存模型有更加清晰的认识。当然,如有偏颇,欢迎指正。在介绍Java内存模型

javalingyu的博客 281

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

别再问什么是Java内存模型了!!

别再问什么是Java内存模型了,看这里! 网上有很多关于Java内存模型的文章,在《深入理解Java虚拟机》和《Java并发编程的艺术》等书中也都有关于这个知识点的介绍。但是,很多人读完之后还是搞不清楚,甚至有的人说自己更懵了。本文,就来整体的介绍一下Java内存模型,目的很简单,让你读完本文以后,就知道到底Java内存模型是什么,为什么要有Java内存模型,Java内存模型解决了什么问题等。 本文中,有很多定义和说法,都是笔者自己理解后定义出来的。希望能够让读者可以对Java内存模型有更加清晰的认识。

冯华 128

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

别再问什么是Java内存模型了,看完这个你就懂了

前面提到的,缓存一致性问题、处理器器优化的指令重排问题是硬件的不断升级导致的。那么,有没有什么机制可以很好的解决上面的这些问题呢?最简单直接的做法就是废除处理器和处理器的优化技术、废除CPU缓存,让CPU直接和主存交互。但是,这么做虽然可以保证多线程下的并发问题。但是,这就有点因噎废食了。所以,为了保证并发编程中可以满足原子性、可见性及有序性。有一个重要的概念,那就是——内存模型。为了保证共享内存的正确性(可见性、有序性、原子性),内存模型定义了共享内存系统中多线程程序读写操作行为的规范。

java_xiaoo的博客 136

Java内存模型详解

前几天,发了一篇文章,介绍了一下JVM内存结构、Java内存模型以及Java对象模型之间的区别。有很多小伙伴反馈希望可以深入的讲解下每个知识点。Java内存模型,是这三个知识点当中最晦涩难懂的一个,而且涉及到很多背景知识和相关知识。 网上有很多关于Java内存模型的文章,在《深入理解Java虚拟机》和《Java并发编程的艺术》等书中也都有关于这个知识点的介绍。但是,很多人读完之后还是搞不清楚,甚...

6143

jvm内存模型和java内存模型

初识java虚拟机,就碰到一系列不懂的问题。我们以前常说java把局部变量放在栈里,new出来的变量放在堆里,然后堆里的数据不定时就给回收了。然后,如果是多线程的话,每个线程自己都有会一个私有的虚拟机栈,运行每个方法时都会创建一个栈帧,栈帧里存储着局部变量啦等信息,方法结束栈帧就出栈。这好像就是我们对java内存模型的第一次理解吧。直至今天,我看了java线程通讯之java内存模型,出现了主内存、...

番茄炒土豆的博客 9445

JAVA内存模型!=JVM内存模型

有很多JAVA开发人员,在被问起:“你知道Java内存模型吗?”,都会回答:“知道,JAVA内存模型分为方法区、堆、…”。虽说“概念”这个词发明出来是为了方便交流和说明问题的,不用太过于较真。但是,答非所问就是你的不对了。如果对两者的概念混淆不清的,希望在看完本文后对你有所帮助。虽然JAVA内存模型!=JVM内存模型,但两者也有一定的关联。通过对JAVA内存模型的了解,能够对并发编程中存在的问题(可见性、原子性、有序性)有清晰的认识以及应对方案。

二蛋的博客 1005
上一篇: 讲个大部分数据结构和算法教科书中都不会讲的问题
下一篇: 静态初始化中不能放入繁重计算,否则会变慢!
大G哥
博客等级 码龄9年 5303粉丝 1408原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值