有几个关于Java内存模型的点,程序员必懂

Java内存模型 Java 内存模型规定了 Java 虚拟机如何与计算机内存 (RAM) 协同工作。Java 虚拟机是整个计算机的模型,因此该模型自然包含一个内存模型,也就是 Java 内存模型。如果你想设计出性能良好的并发程序,理解 Java 内存模型至关重要。Java 内存模型规定了不同线程如何以及何时可以访问其他线程写入共享变量的值,以及如何在必要时同步对共享变量的访问。原始的 Java 内存模型存在不足,因此 Java 1.5 中对 Java 内存模型进行了修订。 阅读详情

一、Java内存模型

硬件处理

        电脑硬件,我们知道有用于计算的cpu、辅助运算的内存、以及硬盘还有进行数据传输的数据总线。在程序执行中很多都是内存计算,cpu为了更快的进行计算会有高速缓存,最后同步至主内存。

        为了使处理器内部的运算单元能够被充分的利用,处理器可能会对输入代码进行乱序执行优化,然后将计算后的结果进行重组,保证该结果和顺序执行的结果是一致的(单位时间内,一个core只能执行一个线程,所以结果的一致仅限一个线程内)。

        Java内存模型是语言级别的模型,它的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取数变量这样的底层细节。

        在内存里,java内存模型规定了所有的变量都存储在主内存(物理内存)中,每条线程还有自己的工作内存,线程对变量的所有操作都必须在工作内存中进行。不同的线程无法访问别线程的工作内存里的内容。下图展示了逻辑上 线程、主内存、工作内存的三者交互关系。

内存交互操作

        Java内存模型定义的8个操作指令来进行内存之间的交互

  • read 读取主内存的值,并传输至工作内存

  • load 将read的变量值存放到工作内存

  • read 好比快递运输车,工作内存好比站点,运输车将快递运输到站点,站点必须得卸货 load 

  • use 将工作内存的变量值,传递给执行引擎

  • assign 执行引擎对变量进行赋值

  • use 好比站点进行快递员分配,站点说我把快递分给你了快递员A。快递员A接收到快递 assign 开始派送。

  • store 工作内存将变量传输到主内存

  • write 主内存将工作内存传递过来的变量进行存储

  • store 和 write 就好理解了,快递员A将快递送到你家门口(store),然后你得签收(write)

  • lock 用作主内存变量,它把一个变量在内存里标识为一个线程独占状态

  • unlock 用作主内存变量,它对被锁定的变量进行解锁

指令规则

        read 和 load、store和write必须成对出现

        assign操作,工作内存变量改变后必须刷回主内存

        同一时间只能运行一个线程对变量进行lock,当前线程lock可重入,unlock次数必须等于lock的次数,该变量才能解锁

        对一个变量lock后,会清空该线程工作内存变量的值,重新执行load或者assign操作初始化工作内存中变量的值。

        unlock前,必须将变量同步到主内存(store/write操作)

二、重排序

从java源码到最终实际执行的指令序列,会经历下面3种重排序

重排序的现象

a=1,b=a 这一组 b依赖a,不会重排序;

a=1,b=2 这一组 a和b没有关系,那么就有可能被重排序执行 b=2,a=1

编译器优化的重排序

        编译器在不改变单线程程序语义的前提下,可以重新安排语句执行顺序

指令级并行的重排序

        现代处理器采用了指令级并行技术将多条指令重叠执行。在不存在数据依赖的时候,处理器可以改变指令执行顺序

内存系统重排序

        处理器使用高速缓存,使得多运算单元加载和存储主内存操作看上去可能在乱序执行

        重排序的代码示例,文章底部的参考文章里有示例,这里就不罗列了。

三、内存屏障

        JMM(java 内存模型) 在不改变程序执行结果的前提下,尽可能的支持处理器的重排序。通过禁止特定特定类型的编译器重排序和处理器重排序,为开发者提供一致的内存可见性保证,如 volatile 、 final 。

        Java编译器在生成指令的时候会在适当位置插入内存屏障来进制特定类型的处理器排序。

        内存屏障说的通俗一点就是一个栏杆,在两个指令之间插入栏杆,后面的指令就不能越过栏杆先执行。

JMM定义的内存屏障指令分为4类

LoadLoad

指令示例 Load1 LoadLoad Load2

确保Load1数据装载一定先于Load2及后续所有Load指令

LoadStore

指令示例 Load1 LoadStore Store2

确保Load1数据装载一定先于Store2及后续所有Store指令

StoreStore

指令示例 Store1 StoreStore Store2

确保Store1主内存落地(从工作内存刷入主存,其它线程可见)一定先于Store2及后续所有Store指令

StoreLoad

指令示例 Store1 StoreLoad Load2

确保Store1主内存落地(从工作内存刷入主存,其它线程可见)一定先于Load2及后续所有Load指令

处理器对重排序的支持

        从上面可以看到不同的处理器架构对重排序的支持也是不一样(其它处理器架构暂不罗列),所以不同的平台JMM的内存屏障施加也略有不同,具体来说,比如 X86 对Load1Load2不支持重排序,那么你就没有必要施加 LoadLoad 屏障。

四、volatile的内存语义

        volatile我们都知道是java的关键字用来保证数据可见性,防止指令重排的效果。包括JUC里AQS Lock的底层实现也是基于volatitle来实现。

volatile写的内存语义

当写一个volatile变量的时候,JMM会把该线程对应的本地内存变量值刷新到主内存

volatile读的内存语义

        当读一个volatile变量的时候,JMM会把线程本次内存置为无效。线程接下来将从主内存中读取共享变量(也就是重新从主内存获取值,更新运行内存中的本地变量)

上面两个语义,保证了volatile变量写入对线程的可见性

volatile内存屏障插入规则

Java 内存模型

volatile内存屏障策略

代码简单示例

class X {
int a, b;
volatile int v, u;
void f() {
    int i, j;
    i = a;// load a  普通load
    j = b;// load b  普通load
    i = v;// load v  volatile load
    // LoadLoad
    j = u;// load u  volatile load
    // LoadStore
    a = i;// store a 普通store  
    b = j;// store b 普通store
    // StoreStore
    v = i;// store v volatile store
    // StoreStore
    u = j;// store u volatile store
    // StoreLoad
    i = u;// load u  volatile load
    // 两个屏障 LoadLoad 和 LoadStore
    j = b;// load b  普通load
    a = i;// store a 普通store
}
}

        上述代码可以套用volatile屏障规则对应。

        当然不同的处理器架构重排序的支持也是不一样,比如X86 只有当 store1 load2 的时候会进行重排序,那么就会省略掉很多类型的内存屏障。

五、final的内存语义

        final在Java中是一个保留的关键字,可以声明成员变量、方法、类以及本地变量。

        被final修饰的变量不能被修改,方法不能被重写,类不能被继承。

        我们暂时把final修饰的称作域,对于final域,编译器和处理器要遵守两个重排序规则

写规则

        在构造函数内对一个final域的写入,与随后把这个被构造的对象的引用赋值给一个引用变量,这两个操作不可重排序

        JMM禁止编译器把final域的写重排序到构造函数之外

        编译器会在final域写入的后面插入 StoreStore 屏障,禁止处理器把final域的写重排序到构造函数之外。

        该规则可以保证在对象引用为任意线程可见之前,对象的final域已经被正确初始化,而普通域无法保障。

读规则

        初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。

        在一个线程中,初次读对象引用与初次读该对象包含的final域,JMM禁止处理器重排序这两个操作。编译器会在读final域操作的前面插入一个LoadLoad屏障。

        该规则保证在读一个对象的final域之前,一定会先读包含这个域的对象引用

六、Java学习视频分享

Java基础:

Java300集,Java必备优质视频_手把手图解学习Java,让学习成为一种享受

Java项目:

【Java游戏项目】1小时教你用Java语言做经典扫雷游戏_手把手教你开发游戏

【Java毕业设计】OA办公系统项目实战_OA员工管理系统项目_java开发

Mac上快速部署DeepSeek模型:Ollama终端操作全指南 本文详细介绍了在Mac上使用Ollama终端快速部署DeepSeek模型的完整指南。从硬件要求、Ollama安装、模型下载运行,到高级配置、可视化界面及常见问题解决,提供了全流程操作步骤与优化技巧,帮助开发者高效搭建本地AI助手,实现稳定、私密的离线使用体验。 阅读详情

相关推荐

半导体工厂自动化实战:用secs4net实现设备与MES系统通信(附完整代码)

本文详细介绍了如何利用secs4net框架实现半导体工厂设备与MES系统的高效通信。通过解析SECS/GEM协议的核心架构、关键业务场景实现及性能优化实践,帮助开发者快速掌握工业自动化通信技术,提升生产效率和系统稳定性。

transformer2023的博客 895

java final 内存_聊聊 Java 内存模型

原标题:聊聊 Java 内存模型*作者:青芒@有赞本文目录Java内存模型重排序内存屏障volatitle的内存语义final的内存语义一、Java内存模型硬件处理电脑硬件,我们知道有用于计算的cpu、辅助运算的内存、以及硬盘还有进行数据传输的数据总线。在程序执行中很多都是内存计算,cpu为了更快的进行计算会有高速缓存,最后同步至主内存,大概的交互如下图 为了使处理器内部的运算单元能够被充分的利用...

weixin_42513269的博客 296

Isaacgym使用操作指南

Isaac Gym 是一个强大的仿真工具,特别适合那些需要进行大规模并行仿真和训练的机器人和强化学习任务。通过 GPU 加速、深度学习集成和丰富的物理仿真能力,Isaac Gym 能够显著提高仿真和训练效率,是机器人学和 AI 研究中的一大利器。

Tony Wey的博客 1万+

java内存模型 final_解读 Java 内存模型

伟人之所以伟大,是因为他与别人共处逆境时,别人失去了信心,他却下决心实现自己的目标。Java内存模型(Java Memory Model)定义了Java的线程在访问内存时会发生什么。这里针对以下几个要点进行解析:重排序可见性synchronizedvolitilefinalDouble-Checked Locking首先了解一下与Java内存模型交互时的指南:* 使用synchronized或vo...

weixin_42303078的博客 289

Silvaco 学习笔记——物理模型:载流子产生复合模型

对载流子的复合机制进行总结

reactortiger的博客 1万+

基于Python爬虫+词云图+情感分析对某东上完美日记的用户评论分析

随着互联网和社交媒体的发展,用户评论成为了消费者表达自己意见和情感的主要途径之一。对于企业来说,深入了解用户对其产品或服务的看法可以帮助他们更好地了解市场需求、产品改进的方向,以及消费者的情感倾向。因此,对用户评论进行分析已经成为了市场研究和商业决策的重要手段之一。

m0_64336780的博客 1万+

final关键字_Java并发关键字final

final的简介final可以修饰变量,方法和类,用于表示所修饰的内容一旦赋值之后就不会再被改变,比如String类就是一个final类型的类。即使能够知道final具体的使用方法,final在多线程中存在的重排序问题很容易忽略,希望能够一起做下探讨。final的具体使用场景final能够修饰变量,方法和类,也就是final使用范围基本涵盖了Java每个地方,下面就分别以锁修饰的位置:变...

weixin_39809168的博客 273

CANbus收发器TJA1051T/3/1J应用原理图设计

该收发器是为汽车工业中的高速CAN应用而设计的,为(一个带有)CAN协议控制器的微控制器)提供差分传输和接收能力。它提供了改进的电磁兼容性(EMC)和静电放电(ESD)性能,还具有:当电源电压关闭时,TJA1051T/3和TJA1051TK/3可以直接与电源电压从3V到5V的微控制器接口。这种实现能够在CAN FD快速阶段以高达5 Mbit/s的数据速率进行可靠的通信。TJA1051T/3和TJA1051TK/3上的VIO输入允许直接连接3 V至5 V微控制器(分别提供SO8和极小的HVSON8封装)

zhusl6688的博客 3607

多线程(56)final关键字在Java内存模型中的作用

在Java中,final关键字可以用于变量、方法和类。当用于变量时,final确保变量一旦被初始化后其值就不能被改变;用于方法时,确保方法不被重写;用于类时,确保类不被继承。对于Java内存模型(JMM)来说,final字段的主要作用是提供初始化安全性,确保对象一旦被构造完成,其final字段的值就不会被改变,并且对于任何获取这些字段的线程来说,final字段的值总是一致的。final。

qq_43012298的博客 637

基于STM32设计自动输液监测系统(241)

该系统集成了液位传感模块、光电传感器、电机模块、按键模块和OLED显示屏等多个功能模块,以实现全面的输液过程监控和控制。液位传感模块能够实时监测输液瓶中的液位,当液位到达限定值时,系统会自动控制步进电机夹紧输液管,并发出报警提醒,确保输液过程不会因液位过低而中断。

1343

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Java多线程 -- 深入理解JMM(Java内存模型) --(六)final

与前面介绍的锁和volatile相比较,对final域的读和写更像是普通的变量访问。对于final域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。 初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。

NowOrNever 9155

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Java 程序员必须掌握的 10 个底层原理,你知道几个?

Java 程序的运行离不开 JVM(Java Virtual Machine)。JVM 的内存结构是理解 Java 底层原理的第一步。程序计数器(Program Counter Register):记录当前线程执行的字节码指令地址。Java 虚拟机栈(Java Virtual Machine Stacks):每个线程私有,用于存储局部变量、操作数栈、动态链接、方法出口等信息。本地方法栈(Native Method Stack):与 Java 虚拟机栈类似,但为 Native 方法服务。

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

程序员秒懂的几个梗,你懂几个?

开源的东西,你不改改,拿过来就用CSS的作用当你删除某行代码的时候其实做程序员和买橘子是一样开发者永远不知道用户是如何使用他设计的产品编写代码,改变世界!程序员的噩梦,你...

Java之间 7549

JVM内存模型和java内存模型

1. JVM内存模型 Java 虚拟机在执⾏ Java 程序的过程中会把它管理的内存划分成若⼲个不同的数据区域。JDK1.8 和之前的版本略有不同,下⾯会介绍到。 首先对于一个进程来说,它包含多个线程,每个线程都有其独立的内存区域,包括:虚拟机栈,本地方法栈和程序计数器。 程序计数器:线程私有 记录当前线程所执行到的字节码的行号。 每个线程都有一个独立的程序计数器,各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存区域。 它是唯一没有OutOfMemoryError情况的内存区域。

m0_45861545的博客 6285

java内存模型

java内存模型 下图就是java内存模型,但是一般讨论的时候不会画这个图,一般画的是java内存模型抽象结构图(在下文)。Thread Stack就是java内存模型抽象结构图中的本地内存,Heap就是java内存模型抽象结构图中的主内存。接下来介绍下图中两个线程内存分配的概念。 java里的堆是运行时的数据区,堆是由垃圾回收来负责的,堆的优势是可以动态的分配内存大小,生存期也不必事先告...

VRival的博客 4341

jvm内存模型和java内存模型

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

番茄炒土豆的博客 9446

硬件内存模型到 Java 内存模型,这些硬核知识你知多少?

Java 内存模型跟上一篇 JVM 内存结构很像,我经常会把他们搞混,但其实它们不是一回事,而且相差还很大的,希望你没它们搞混,特别是在面试的时候,搞混了的话就会答非所问,影响你的面试成绩,当然也许你碰到了半吊子面试官,那就要恭喜你了。Java 内存模型比 JVM 内存结构复杂很多,Java 内存模型有一个规范叫:《JSR 133 :Java内存模型与线程规范》,里面的内容很丰富,如果你没看过的话...

平头哥的技术博文 2734

面试必问:Java 内存模型的3个特性

前言 Java内存模型(Java Memory Model ,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能得到一致效果的「机制及规范」。 JMM与Java内存区域是两个容易混淆的概念,这两者既有差别又有联系: 区别 「两者是不同的概念层次」。「Java 内存模型是抽象的,它是用来描述一组规则」,通过这个规则来控制...

vincent 6113

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

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

java_xiaoo的博客 137

有哪些是程序员才懂的梗?

同学们,程序员的梗,看似是调侃、是段子,但背后藏着的是这群人的真实生活。如果你也是程序员,或者正在成为程序员的路上,记住这些梗不仅是笑点,也是你融入圈子的方式。更重要的是,它们告诉我们:生活再难,代码再乱,只要会自嘲,总能找到快乐的出口。所以,当你在社交平台上看到程序员用“Hello World”打招呼时,别觉得奇怪,那只是他们的“职业习惯”而已。程序员界有个“黑话”叫**“删库跑路”**,听着就有点黑社会的意思,但其实这是程序员的职业“恐怖片”。所以,程序员的修仙文化,既是一种吐槽,也是一种无奈。

m0_61562916的博客 1570

思考:Java内存模型和硬件内存模型

前一阵在看volatile的原理,看到内存屏障和缓存一致性,发现再往底层挖就挖到了硬件和Java内存模型。这一块是自己似懂非懂的知识区,我一般称之为知识混沌区。因此整理这一篇文章。什么是内存模型(Memory Model)呢?它是系统和程序员之间的规范,它规定了存储器访问的行为,并影响到了性能。并且,Memory Model有多层,处理器规定、编译器规定、高级语。

bigben 1101

CPU内存模型、Java内存模型和JVM内存模型

CPU内存模型、Java内存模型和JVM内存模型

qq_40577332的博客 1583

Java开发者必知:JVM内存模型

理解JVM内存模型对于优化Java程序的性能至关重要。JVM的内存划分不仅有助于我们理解程序如何执行,还能帮助我们识别内存问题,并采取有效措施进行调优。通过了解堆、栈、方法区、程序计数器等内存区域的作用,以及JVM垃圾回收机制的工作原理,我们可以更好地掌握Java程序的执行过程,写出更高效、稳定的代码。

qq_40697623的博客 859

产品经理必懂的技术那点事儿 pdf_产品经理必懂的技术那点事儿 唐韧

昨天我从一个吃货的角度谈论了《给产品经理讲技术》一书,今天我尝试从一个女性的角度谈谈我对《产品经理必懂的技术那点事儿》的看法。一、产品思维与技术思维首先,上一段只有程序员才能看懂的段子:老婆给当程序员的老公打电话:“下班顺路买一斤包子带回来,如果看到卖西瓜的,买一个。”当晚,程序员老公手捧一个包子进了家门...老婆怒道:“你怎么就买了一个包子?!”老公答曰:“因为看到了卖西瓜的。”老婆...

weixin_39683172的博客 2799

小白也能看懂的Java内存模型

前言 Java并发编程系列开坑了,Java并发编程可以说是中高级研发工程师的必备素养,也是中高级岗位面试必问的问题,本系列就是为了带读者们系统的一步一步击破Java并发编程各个难点,打破屏障,在面试中所向披靡,拿到心仪的offer,Java并发编程系列文章依然采用图文并茂的风格,让小白也能秒懂。 Java内存模型(Java Memory Model)简称J M M,作为Java并发编程系列的开篇,它是Java并发编程的基础知识,理解它能让你更好的明白线程安全到底是怎么一回事。 内容大纲 硬件内存模型 程序

程序猿阿星 2512
上一篇: Java书籍中很少提到的知识点有哪些?
下一篇: 不能让你放弃学Java的理由是什么?
程序媛_小白
博客等级 码龄5年 322粉丝 163原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值