[Java虚拟机]Java内存模型与线程

java虚拟机-java内存模型与线程 java内存模型与线程java内存模型主内存和工作内存内存间的交互volatitle关键字可见性禁止指令重排long和double型变量的特殊规则原子性,可见性,有序性先行先发生原则 java内存模型 java虚拟机规范试图定义一种java内存模型来屏蔽掉各种硬件和操作系统的内存访问差异,实现java程序在各平台下都能达到一致的并发效果。c与c++直接使用物理硬件(操作系统的内存模型),因此需要针对不同平台编写程序。 主内存和工作内存 java内存模型的主要目标是定义程序中各变量的访问规则,即虚拟机中将变量 阅读详情

深入理解Java虚拟机读书笔记


第12章

主内存和工作内存

java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。为了获得较好的执行效能,Java内存模型咩有并没有限制执行引擎使用处理器的特定寄存器或缓存来和主内存进行交互,也没有限制即时编译器调整代码执行顺序这类权利。

Java内存模型规定了所有的变量都存储在主内存中(Main Memory)中(此处的主内存和介绍物理硬件时的主内存名字一样,两者也可以互相类比,但此处仅是虚拟机内存的一部分)。每条线程还有自己的工作内存(Working Memory,可与前面所讲的处理器高速缓存类比),线程的工作内存中保存了该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取,赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程也无法直接访问对方工作内存中的变量,线程间变量的传递需要通过主内存来完成,线程、主内存、工作内存的交互关系如图:

这里写图片描述

内存间交互操作

关于主内存和工作内存之间具体的交互协议,即一个遍历那个如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节,Java内存模型中定义了一下八种操作来完成:

  • lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态。
  • unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
  • read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。
  • load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
  • use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。
  • assign(赋值):作用于工作内存的变量,它把一个从执行引擎收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码时执行这个指令。
  • store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。
  • write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。

如果要把一个变量从主内存复制到工作内存,那就要按顺序执行read和load操作,如果要把变量从工作内存同步回主内存,就要按照顺序地执行store和write操作。注意,Java内存模型只要求上述两个操作必须按顺序执行,而没有保证必须是连续执行。Java内存模型规定了在执行上述八种基本操作时必须满足时必须满足如下规则:

  • 不允许read和load、store和write操作之一单独出现
  • 不允许一个线程丢弃它的最近的assign操作
  • 不允许一个线程无原因的(没有发生过任何assign操作)把数据从线程的工作内存同步到主内存中
  • 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量
  • 一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁
  • 如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。
  • 如果一个变量事先没有被lock锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定住的变量。
  • 对一个变量执行unlock操作之前,必须先把此变量同步回主内存中(执行store和write)
对于volatile型变量的特殊规则

当一个变量被定义成volatile之后,它将具备两种特性,第一是保证此变量对所有线程的可见性,这里的可见性是指当一条线程修改了这个变量的值,新值对于其他的线程是可以立即得知的。

由于volatile变量只能保证可见性,在不符合以下两条规则的运算场景中,我们仍然要通过加锁(使用synchronized或java.util.concurrent中的原子类)来保证原子性

  • 运算结果并不依赖于变量的当前值,或者能够确保只有单一的线程修改变量的值
  • 变量不需要与其他的状态变量共同参与不变约束

volatile变量读操作的性能消耗与普通变量几乎没有什么差别,但是写操作则可能会慢上一些,因为它需要在本地代码中插入许多内存屏障(Memory Barrier或Memory Fence)指令来保证处理器不发生乱序执行。不过即便如此,大多数场景volatile的总开销仍然要比锁来的低。

对于long和double型变量的特殊规则

Java内存模型要求对于lock、unlock、read、load、assign、use、store和write这八个操作都具有原子性,但是对于64位的数据类型(long和double),允许虚拟机将没有被volatile修饰的64位数据的读写操作划分为两次32位的操作来进行,即允许虚拟机实现选择可以不保证64位数据类型的load、store、read和write这四个操作的原子性。

原子性、可见性与有序性

Java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性,volatile关键字本生就包含了禁止指令重排序的语义,而synchronized则是由“一个变量在同一时刻只允许一条线程对其进行lock操作”这条规则获得的,这个规则决定了持有同一个锁的两个同步代码块只能串行的进入。

先行发生原则

先行发生是Java内存模型中定义的两项操作之间的偏序关系,如果说操作A先行发生于操作B,其实就是说在发生操作B之前,操作A产生的影响能被操作B观察到,“影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等。

以下是Java内存模型下一些天然的先行发生关系,这些关系无需任何同步器协助就已经存在。

  • 程序次序规则(Program Order Rule):在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。准确的说是控制流顺序而不是程序代码顺序,因为要考虑分支、循环等结构。
  • 管程锁定规则(Monitor Lock Rule):一个unlock操作先行发生于后面对同一个锁的lock操作。这里必须强调的是同一个锁,而后面是指事件上的先后顺序。
  • volatile变量规则(Volatile Variable Rule):对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的后面同样是指时间上的先后顺序。
  • 线程启动规则(Thread Start Rule):Thread对象的start()方法先行发生于此线程的每一个动作。
  • 线程终止规则(Thread Termination Rule):对线程所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join() 方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。
  • 线程中断规则(Thread Interruption Rule):对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。
  • 对象终结规则(Finalizer Rule):一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。
  • 传递性(Transitivity):如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。
线程的实现

线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件I/O等),又可以独立调度(线程是CPU调度的最基本单位)。

实现线程主要有三种方式:

  1. 使用内核线程实现
  2. 使用用户线程实现
  3. 混合实现
  4. Java线程的实现
Java线程调度

线程调度是指系统为线程分配处理器使用权的过程,主要调度方式有两种,分别是协同式(Cooperative Threads-Scheduling)线程调度和抢占式(Preemptive Threads-Scheduling)线程调度。

使用协同式调度的多线程系统,线程的执行时间由线程本身来控制,线程把自己的工作执行完了之后,要主动通知系统切换到另外一个线程上去。协同式多线程的最大好处是实现简单,而且由于线程要把自己的事情干完后才会进行线程切换,切换操作对自己是可知的,所以没有什么线程同步的问题。坏处是线程执行时间不可控制,甚至如果一个线程编写有问题,一直不告知系统进行线程切换,那么程序就会一直阻塞在那里。

抢占式调度的多线程系统,那么每个线程将由系统来分配执行时间,线程的切换不由线程本身来决定(在Java中,Thread.yield()可以让出执行时间,但是要获取执行时间的话,线程本身是没有什么办法的)。在这种实现线程调度的方式下,线程的执行时间是系统可控的,也不会有一个线程导致整个进程阻塞的问题,Java使用的线程调度方式就是抢占式调度。

状态转换

Java定义了5种进程状态

  • 新建(New):创建后尚未启动的线程处于这种状态。
  • 运行(Runnable):Runnable包括了操作系统状态中的Running和Ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待CPU为它分配执行时间。
  • 无限期等待(Waiting):处于这种状态的进程不会被分配CPU执行时间,它们要等待被其他线程显示的唤醒。以下方法会让线程陷入无限期的等待状态:
    • 没有设置Timeout参数的Object.wait()方法
    • 没有设置Timeout参数的Thread.join()方法
    • LockSupport.park()方法
  • 限期等待(Timed Waiting):处于这种状态的进程不会被分配CPU执行时间,不过无需等待被其他线程显示的唤醒,在一定时间之后它们会由系统自动唤醒。以下方法会让线程进入限期等待状态:
    • Thread.sleep()方法
    • 设置了Timeout参数的Object.wait()方法
    • 设置了Timeout参数的Thread.join()方法
    • LockSupport.parkNanos()方法
    • LockSupport.parkUnitil()方法
  • 阻塞(Blocked):进程被阻塞了,阻塞状态和等待状态的区别是:阻塞状态在等待着获取到一个排它锁,这个事件将在另一个线程放弃这个锁的时候发生;而等待状态则是在等待一段时间,或者唤醒动作的发生。在程序等待进入同步区域的时候,线程将进入这种状态。
  • 结束(Terminated):已终止线程的线程状态,线程已经结束执行。
Java 虚拟机JVM内存模型 Java 虚拟机JVM内存模型与垃圾收集策略,看完此资料,JVM将不再话下 立即下载

相关推荐

Embarcadero Dev-C++ 6.3安装教程【保姆级】

Embarcadero Dev-C++ 6.3安装教程,保姆级教程~

Thebest_jack的博客 1万+

深入学习java虚拟机||JVM内存结构五大模型

​ 定义:全称P r o g r a m C o u n t e r R e gis t e r 程 序 计 数 器 ( 寄 存 器 ) 作 用 :是 记 住 下 一 条j v m 指 令 的 执 行 地 址 特点: 是 线 程 私 有 的 不 会 存 在 内 存 溢 出(java中唯一一个不会存在内存溢出的区域) 作用:java程序要想执行,首先会编译成字节码,也就是计算机能够看懂的二进制文件,但是呢操作系统并不能认识这些二进制字节码,比如一条命令很有可能产生很

adru的博客 769

GD32H7 SPI驱动实战:手把手教你用SPI3连接外部Flash(W25Q128)并实现读写

本文详细介绍了基于GD32H7系列MCU的SPI3接口驱动W25Q128外部Flash的全流程开发指南。从硬件设计、引脚配置到SPI3外设深度配置,再到底层通信函数实现和高级功能优化,提供了完整的解决方案。特别针对高速读取、DMA传输和信号完整性等关键环节进行了优化,确保系统在-40℃~85℃范围内稳定工作。

weixin_28729205的博客 379

JVM 虚拟机 ----> Java 内存模型(JMM)

Heap堆区,用于存放对象实例和数组的内存区域Heap堆是JVM所管理的内存中最大的一块区域,被所有线程共享的一块内存区域。堆区中存放对象实例,“几乎”所有的对象实例以及数组都在这里分配内存Java世界中“几乎”所有的对象都在堆中分配,但是,随着JIT编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。从JDK 1.7。

weixin_62587914的博客 3170

告别F5失灵!手把手教你为Cursor配置.Net Core控制台项目专属调试环境

本文详细指导如何在Cursor编辑器中为.Net Core控制台项目配置专属调试环境,解决F5失灵等常见问题。从调试器选择到launch.json配置,再到高级调试技巧,帮助开发者高效搭建完整的调试工具链,提升开发效率。

weixin_28834765的博客 284

别再只做游戏了!用虚幻引擎5(UE5)给你的工厂车间做个数字双胞胎(附数据对接教程)

本文详细介绍了如何利用虚幻引擎5(UE5)构建工业数字孪生系统,实现工厂车间的智能可视化。通过UE5的高质量渲染和实时数据处理能力,结合OPC UA和MQTT协议,打造高效的数据对接方案,提升异常识别和设备管理效率。文章还分享了模型优化、可视化设计及典型工业场景的实战案例,助力企业迈向工业4.0。

weixin_33738555的博客 206

Jvm基础篇-09-Java内存模型与线程

多任务处理在现代计算机操作系统中几乎已是一项必备的功能了。在许多场景下,让计算机同时去做几件事情,不仅是因为计算机的运算能力强大了,还有一个很重要的原因是计算机的运算速度与它的存储和通信子系统的速度差距太大,大量的时间都花费在磁盘I/O、网络通信或者数据库访问上。如果不希望处理器在大部分时间里都处于等待其他资源的空闲状态,就必须使用一些手段去把处理器的运算能力“压榨”出来,否则就会造成很大的性能浪费,而让计算机同时处理几项任务则是最容易想到,也被证明是非常有效的“压榨”手段。

Alan0517 722

AGV舵轮选型实战:从核心参数到精准计算的完整指南

本文提供了一份详尽的AGV舵轮选型实战指南,强调从经验决策转向数据驱动。文章系统讲解了如何将工况需求转化为核心参数,并通过牵引力、扭矩、功率等关键计算步骤,指导工程师完成精准选型,避免因选型不当导致的运行故障与效率低下。

醉三国 495

Java虚拟机——Java内存模型

把变量值存储到内存内存中取出变量值。

肇秋贰拾捌的博客 582

YOLOv11涨点改进| SCI一区2026 |独家创新首发、特征融合改进篇|引入FAFM特征对齐融合模块,通过特征对齐和融合两个阶段,助力多模态融合小目标检测,小目标检测,SAR图像目标检测高效涨点

🔥本文提出了一种改进YOLOv11网络模型的方法,通过引入FAFM(特征对齐融合模块)来解决多模态目标检测中的特征空间错位问题。FAFM模块采用可变形卷积和内容引导注意力机制,有效实现了跨模态特征对齐与融合,充分利用了不同模态间的互补信息。该方法在保持模型轻量化的同时,显著提升了目标检测精度和鲁棒性,特别是在复杂背景和模态差异较大的场景下表现突出。文章详细介绍了FAFM模块的结构、原理、优势,并提供了完整的代码实现和模型配置方案,为多模态目标检测任务提供了实用的技术参考。

Ai缝合怪、助力小伙伴高效发论文 267

【android bluetooth 案例分析 01】【HiCar 详解 3】【hicar时如何交换Wifi参数的】

如果直接使用 L2CAP(不经过 RFCOMM),会需要额外的协议来保证可靠性,而 RFCOMM 天然支持。BLE 广播的数据长度受限(31 字节 / 255 字节扩展),不适合传输复杂的 Wi-Fi 连接参数。使用 RFCOMM 传输参数,可以兼容不同厂商的车机和手机,而无需依赖特殊的蓝牙功能。手机解析这些参数,并使用 Wi-Fi Direct 连接到车机。,然后才能让 Wi-Fi Direct 进行真正的数据传输。,适合传输 Wi-Fi 连接参数等关键数据。,可以安全地交换 Wi-Fi 连接信息。

奔跑吧 android 的博客 1740

Java并发编程(二)内存模型及线程池

Java之并发编程(二)

folyh 919

[网络安全自学篇] 七十三.WannaCry勒索病毒复现及分析(四)蠕虫传播机制全网源码详细解读

这是作者网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您喜欢,一起进步。前文分享了逆向分析OllyDbg动态调试工具的基本用法,包括界面介绍、常用快捷键和TraceMe案例分析。这篇文章将继续详细讲解WannaCry蠕虫的传播机制,带领大家详细阅读源代码,分享WannaCry勒索病毒是如何传播感染的。作者分析该病毒一个月,一方面觉得自己技术菜,另一方面深知系统安全需要坚持,继续加油。希望文章对您有所帮助~

杨秀璋的专栏 1万+

深入理解Java虚拟机之Java内存模型与线程

1 概述 除了充分利用计算机处理器的能力外,一个服务端同时对多个客户端提供服务则是另一个更具体的并发应用场景。衡量一个服务性能的高低好坏,每秒事务处理数(TransactionsPer Second,TPS)是最重要的指标之一,它代表着一秒内服务端平均能响应的请求总数,而TPS值与程序的并发能力又有非常密切的关系。对于计算量相同的任务,程序线程并发协调得越有条不紊,效率自然就会越高;反之,线程之...

striveb的博客 502

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

《深入理解Java虚拟机》之Java内存模型与线程

阅读《深入理解Java虚拟机》第2版,结合JDK8的读书笔记。当前文章为书本的第12章节。 12.1.概述 本章节将介绍虚拟机如何实现多线程,多线程之间由于线程共享和竞争数据而导致的一系列问题以及解决方案。 TPS(Transactions Per Second):它代表着一秒内服务端平均能相应的请求总数。 12.2.硬件的效率与一致性 计算机的存储设备和处理器的运算速度存在比较大的差异,...

瑾析编程 265

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java 虚拟机内存模型—线程私有

文章目录JVM 内存模型线程私有区域程序计数器虚拟机栈栈帧的组成StackOverflowError本地方法栈逃逸分析优化线程私有部分的回收问题参考 JVM 内存模型 .java 源文件 -> javac 工具编译 -> .class 文件 -> JVM 解析 -> 010101 机器码 -跑在不同的操作系统上。 基于上面的流程可以看出,java 是一个跨平台语言。 ...

六号表哥 1336

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Java虚拟机-Java内存模型和线程

主要介绍Java内存模型和线程。

weixin_56446161的博客 92

java虚拟机之Java内存模型与线程

Java内存模型与线程 Java内存模型 主内存与工作内存 Java内存模型主要目标:定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量(Variable)与Java编程中的变量略有区别,它包括实例变量/静态字段和构成数组对象的元素,不包括局部变量和方法参数(线程私有)。为获得较好的执行效能,Java内存模型并没有限制执行引擎使用处理器的特定寄存...

mr_x的博客 429

深入理解Java虚拟机系列(四)--Java内存模型和线程

深入理解Java虚拟机系列(四)--Java内存模型和线程系列文章目录 系列文章目录 深入理解Java虚拟机系列文章

Zong_0915的博客 275

Java虚拟机08——Java内存模型与线程

硬件的效率与一致性 绝大多数的运算任务都不可能只靠处理器“计算”就能完成,处理器至少要与内存交互,如读取运算数据、存储运算结果等。由于计算机的存储设备与处理器的运算速度有接数量级的差距,所以现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存(Cache)来作为内存与处理器之间的缓冲:将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存中,这样处...

小宝的博客 240

深入理解 Java 虚拟机:Java 内存模型与线程

深入理解 Java 虚拟机:Java 内存模型与线程什么是内存模型?什么是高速缓存?缓存一致性Java 内存模型主内存工作内存内存间的交互操作volatile 关键字对所有线程可见性禁止指令重排序Java 内存模型的特征原子性可见性有序性synchronized 缺点先行发生原则“天然的” 先行发生关系 什么是内存模型? 内存模型: 可以理解为,在特定的操作协议下,对特点的内存或高速缓存进行读写访问的过程的抽象。 什么是高速缓存? 在运算时,将需要使用到的数据从内存复制到缓存(Cache)中,以此让计算能更

乐之终曲 1708

学习java虚拟机 - 内存模型与线程

学习java虚拟机 - 内存模型与线程 一、为什么   Java虚拟机规范试图定义一种Java内存模型(Java Memory Model, JMM)来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存一致的内存访问效果。 二、主内存和工作内存   Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中奖变量存...

weixin_30345055的博客 173

Java虚拟机6 内存模型、线程、锁

一致性问题 高速缓存 (Cache) 由于计算机的CPU与内存运算速度有几个数量级的差距,所以加入一层或多层高速缓存,作为内存与处理器之间的缓冲:将运算使用到的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存之中。 缓存一致性 (Cache Coherence) 每个处理器内核都有自己的高速缓存,而它们又共享同一主内存,如下图: 当多个处理器的运算涉及同一块内存时,可能导致各自的缓存数据不一致。为了解决一致性的问题,需要各个处理器访问缓存时都遵循一些协议。 内存模型:在特定的操作协议下,

c39660570的博客 289

深入理解Java虚拟机—Java内存模型与线程

上一篇:深入理解Java虚拟机——(13) Java内存模型与线程 一. 硬件的效率和一致性 让计算机并发执行若干个运算任务和更充分地利用计算机处理器的效能之间看起来是因果关系,但实际上没那么简单。CPU的运算能力十分强大,但是任何任务都不太可能单单靠CPU就能够完成,比如读取内存,存储的数据,网络的请求等IO操作是很难消除的,更糟糕的是存储设备与CPU之间的运算差距过大,所以在内存和CPU之间又会加一道高速缓存介质进行提速。为了充分利用CPU的性能,通常会采取异步IO的方式进行,这样CPU可以去处理其他的

haiyanghan的博客 266
上一篇: [Android进阶]Android消息机制
下一篇: [Java基础]Java总结篇
陶程
博客等级 码龄12年 360粉丝 56原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值