【深入浅出JVM原理及调优】「搭建理论知识框架」全方位带你探索和分析JMM并发模型之(重排序机制)

全方位带你探索和分析JMM并发模型之重排序机制

  • 专栏介绍
  • 前提准备
  • 面向人群
  • 知识脉络
    • 重排序
    • 数据依赖性
      • 读后写依赖(Read-After-Write Dependency)
      • 写后读依赖(Write-After-Read Dependency)
      • 写后写依赖(Write-After-Write Dependency)
        • 代码案例
    • as-if-serial语义
      • as-if-serial的问题和局限性
        • 依赖关系分析
        • 两种执行顺序场景
        • 程序顺序规则
        • 重排序对多线程的影响
          • 操作1和操作2的重排序问题分析
          • 操作3和操作4的重排序问题分析
    • 总结分析
      • As-if-serial
      • Happens-Before

专栏介绍

学习JVM需要一定的编程经验和计算机基础知识,适用于从事Java开发、系统架构设计、性能优化、研究学习等领域的专业人士和技术爱好者。

前提准备

  • 编程基础:具备良好的编程基础,理解面向对象编程(OOP)的基本概念,熟悉Java编程语言。
  • 数据结构与算法:对基本的数据结构和算法有一定了解,理解内存管理、线程操作等基本概念。

面向人群

学习本专栏以及本章内容的前提和适用人群如下:

  • Java开发人员:JVM是Java程序的核心执行引擎,因此Java开发人员需要深入了解JVM的工作原理和运行机制,以优化程序性能并解决相关问题。
  • 系统架构师和高级工程师:对系统整体性能、稳定性有较高要求的人群,有必要深入理解JVM以优化系统性能。
  • Java程序员和技术爱好者:具备一定Java编程经验,有意向深入了解JVM内部工作原理的人群。
  • 研究人员和学生:从事计算机科学相关研究或学习的人群,有兴趣深入研究JVM内部原理和优化方法。
  • JVM运维工程师:负责JVM性能优化、故障排查和调优的专业人员,需要对JVM有深入的理解。

知识脉络

每位Java开发者都了解到Java字节码是在Java运行时环境(JRE)上执行的。JRE包含了最为关键的组成部分:Java虚拟机(JVM),它负责分析和执行Java字节码。通常情况下,大多数Java开发者无需深入了解虚拟机的内部运行原理。即使对虚拟机的运行机制不甚了解,也不会对开发工作产生太多影响。然而,对JVM有一定了解的话,将更有助于深入理解Java语言,并解决一些看似困难的问题。

本专栏全面系统地剖析了特定虚拟机产品(即HotSpot,Oracle官方虚拟机)的实现,本人不仅深刻地讲解了看似深奥的原理,还提供了大量易于上手的实践案例,下面是总体的JVM相关的知识拓扑架构。

在这里插入图片描述

tips:当然还有一些最新的JVM特性未在这张图并非展示本专栏的全部内容,另外还包含了最新的JVM特性。

重排序

在计算机领域,软件技术和硬件技术共同的目标是在不改变程序执行结果的前提下尽可能地提高并行度。编译器和处理器都致力于实现这一目标,并且Java内存模型(JMM)也遵循这一原则。

数据依赖性

当两个操作访问同一个变量时,并且其中至少一个操作是写操作,这两个操作之间就存在数据依赖关系。数据依赖关系可以被分为以下三种类型:

在这里插入图片描述

读后写依赖(Read-After-Write Dependency)

当一个写操作在一个读操作之后发生时,存在读后写依赖。换句话说,后续的读操作在之前的写操作完成之后才能获取到最新的数据。

// 读一个变量之后,再写这个变量。
a=b;
b=1;

写后读依赖(Write-After-Read Dependency)

当一个读操作在一个写操作之后发生时,存在写后读依赖。这意味着读操作获取的是在之前写操作完成时的旧数据,而不是最新的数据。

//写一个变量之后,再读这个位置。
a=1;
b=a;

写后写依赖(Write-After-Write Dependency)

当两个或多个写操作在彼此之间发生时,存在写后写依赖。这意味着后续的写操作依赖于之前的写操作的结果。

代码案例
// 写一个变量之后,再写这个变量。
a=1;
a=2;

如果对上面的操作进行重排序,可能会导致程序的执行结果发生变化。编译器和处理器会遵守数据依赖性原则,不会改变具有数据依赖关系的两个操作的执行顺序,以确保结果的正确性。

注意,上述讨论的数据依赖性仅适用于在单个处理器中执行的指令序列或单个线程中执行的操作。编译器和处理器不考虑不同处理器之间或不同线程之间的数据依赖性。因此,为确保多线程程序的正确性,需要使用同步机制,如锁、原子操作等,以保证数据的正确读取和写入。这样可以解决不同线程之间的并发冲突和重排序问题,确保程序的正确执行。

as-if-serial语义

as-if-serial语义指的是无论编译器和处理器如何进行重排序,单线程程序的执行结果不能被改变。

as-if-serial的问题和局限性

编译器、运行时环境和处理器都必须遵守as-if-serial语义,这意味着编译器、运行时环境和处理器可以对操作进行重排序,只要其不改变程序在单线程执行下的结果。通过这种优化,可以提高并行性和性能。

as-if-serial语义确保对于单线程程序来说,其执行结果始终与按照顺序执行所有操作的结果一致。

double pi = 3.14;  //A
double r = 1.0; //B
double area = pi *r * r; //C

上面三个操作的数据依赖关系如下图所示:

在这里插入图片描述

依赖关系分析

在上述图示中,表明了A和C之间存在数据依赖关系,并且B和C之间也存在数据依赖关系。这确保了在最终的指令序列中,C不能被重排序到A和B的前面。这样做是为了确保程序的结果不会被改变。

A和B之间并没有数据依赖关系,这意味着在编译器和处理器的优化下,A和B之间的执行顺序可以重排序。这种重排序不会影响程序的结果,因为它们之间没有数据依赖关系。

在指令序列的执行中,可以出现两种不同的执行顺序,而结果是等效的。这允许编译器和处理器在没有改变程序语义的情况下进行优化,提高并行性和性能。

两种执行顺序场景

在这里插入图片描述
按程序顺序的执行结果:area=3.14,重排序后的执行结果:area=3.14。

程序顺序规则

根据happens-before的程序顺序规则,上面计算圆的面积的示例代码存在三个happens-before关系:对于第三个happens-before关系,根据happens-before的传递性,可以推导出A happens-before B。
在这里插入图片描述
尽管A happens-before B,根据之前提到的重排序后的执行顺序,B可以在A之前执行。在Java内存模型(JMM)中,happens-before关系并不要求A一定要在B之前执行。JMM只要求前一个操作(执行结果)对后一个操作可见,并且前一个操作按顺序排在第二个操作之前。

在这种情况下,操作A的执行结果不需要对操作B可见。而且,重排序操作A和操作B后的执行结果与按照happens-before顺序执行操作A和操作B的结果是一致的。因此,JMM认为这种重排序是合法的,它允许这种重排序的优化。

注意,JMM的目的是确保多线程程序的正确性和一致性,而不是强制要求按照规定的顺序执行。JMM允许对指令进行适当的重排序以提高性能和并发度,同时确保程序的语义和结果与顺序执行的情况一致。

重排序对多线程的影响

现在让我们来看看,重排序是否会改变多线程程序的执行结果。请看下面的示例代码:

class ReorderExample {
int a 0;
boolean flag false;
public void writer(){
  a=1; //1
  flag = true; //2
}
Public void reader({
  if (flag) //3
   int i=a*a; //4
}

flag变量是个标记, 用来标识变量a是否已被写入。这里假设有两个线程A和B,A首先执行writer方法, 随后B线程接着执行reader方法。线程B在执行操作4时,不一定能看到线程A在操作1对共享变量a的写入结果。

操作1和操作2的重排序问题分析

由于操作1和操作2没有数据依赖关系,编译器和处理器可以对这两个操作重排序;同样,操作3和操作4没有数据依赖关系,编译器和处理器也可以对这两个操作重排序。让我们先来看看,当操作1和操作2重排序时,可能会产生什么效果,请看下面的程序执行时序图:

在这里插入图片描述
如上图所示,操作1和操作2做了重排序。程序执行时,线程A首先写标记变量flag, 随后线程B读这个变量。由于条件判断为真, 线程B将读取变量a。此时,变量a还根本没有被线程A写入,在这里多线程程序的语义被重排序破坏了!

操作3和操作4的重排序问题分析

下面再让我们看看,当操作3和操作4重排序时会产生什么效果(借助这个重排序,可以顺便说明控制依赖性)。下面是操作3和操作4重排序后,程序的执行时序图:
在这里插入图片描述
操作3和操作4存在控制依赖关系。当代码中存在控制依赖性时,会影响指令序列执行的并行度。为此, 编译器和处理器会采用猜测(Speculation) 执行来克服控制相关性对并行度的影响。以处理器的猜测执行为例,执行线程B的处理器可以提前读取并计算a*a,然后把计算结果临时保存到一个名为重排序缓冲(reorder buffer ROB) 的硬件缓存中。当接下来操作3的条件判断为真时, 就把该计算结果写入变量i中。

从图中我们可以看出,猜测执行实质上对操作3和4做了重排序。重排序在这里破坏了多线程程序的语义!

在单线程程序中,对存在控制依赖的操作重排序,不会改变执行结果(这也是as-if-serial语义允许对存在控制依赖的操作做重排序的原因) ; 但在多线程程序中,对存在控制依赖的操作重排序,可能会改变程序的执行结果。

总结分析

As-if-serial

数据依赖关系对于确保程序结果的准确性至关重要,但是在没有数据依赖关系的情况下,编译器和处理器可以对指令重排序以优化性能,并且仍然必须遵循程序的as-if-serial语义。

As-if-serial规则确保在单线程环境下,重排序后的指令序列的结果与按顺序执行所有操作的结果一致。这意味着重排序不能改变单线程程序的执行结果。

此外,as-if-serial语义还解决了内存可见性问题。编译器,并且处理器在执行指令的过程中,会确保在多个线程之间正确地处理共享内存的读写操作,以保证单线程程序的数据一致性。

Happens-Before

根据happens-before关系的定义,我们可以看出JMM也遵循这一目标。happens-before关系确保了在多线程环境中,编写的程序的顺序和语义与按序执行的情况一致,但并不限制编译器和处理器对指令进行优化和重排序。

编译器和处理器会根据happens-before关系和as-if-serial语义,对指令进行优化和重排序,以提高并行性和性能,同时确保程序的执行结果与顺序执行的结果一致。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/308237.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

离线AI聊天清华大模型(ChatGLM3)本地搭建

在特定的情况下,要保证信息安全的同时还能享受到AIGC大模型带来的乐趣和功能,那么,离线部署就能帮助到你,最起码,它是一个真正可用的方案。 大模型本身清华的 (ChatGLM3),为的是对中文支持友好&#xff0c…

重学JavaScript高级(八):ES6-ES12新增特性学习

ES6-ES12新增特性学习 ES6–对象字面量增强 属性的简写方法的简写计算属性名 let name "zhangcheng" //我想让sum作为obj的key值 let objKey "sum" let obj {//属性名的简写name//等同于name:name//方法的简写running(){}//等同于running:function()…

寒武纪显卡实现softmax算子

寒武纪显卡实现softmax基本逻辑 寒武纪实现softmax包括下面5个步骤,我们也采取5个kernel来实现softmax: unionMaxKernel(float* middle, float* source1, int num),这个kernel使用的任务类型是union1,其中middle的长度为taskDim&…

如何设置电脑桌面提醒,电脑笔记软件哪个好?

对于大多数上班族来说,每天要完成的待办事项实在太多了,如果不能及时去处理,很容易因为各种因素导致忘记,从而给自己带来不少麻烦。所以,我们往往会借助一些提醒类的软件将各项任务逐一记录下来,然后设置上…

时序分解 | Matlab实现CPO-VMD基于冠豪猪优化算法(CPO)优化VMD变分模态分解时间序列信号分解

时序分解 | Matlab实现CPO-VMD基于冠豪猪优化算法(CPO)优化VMD变分模态分解时间序列信号分解 目录 时序分解 | Matlab实现CPO-VMD基于冠豪猪优化算法(CPO)优化VMD变分模态分解时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 【原创】CPO-VMD【24年新算法…

Mysql系列-1.Mysql基本使用

👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术🔥如果感觉博主的文章还不错的…

【揭秘APT攻击】——内网渗透实战攻略,带你领略网络安全的绝密世界!

🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:"没有罗马,那就自己创造罗马~" 目录 介绍 什么是内网? 什么是内网渗透? 内网渗透的目的: 内网…

leetcode:1716. 计算力扣银行的钱(python3解法)

难度:简单 Hercy 想要为购买第一辆车存钱。他 每天 都往力扣银行里存钱。 最开始,他在周一的时候存入 1 块钱。从周二到周日,他每天都比前一天多存入 1 块钱。在接下来每一个周一,他都会比 前一个周一 多存入 1 块钱。 给你 n &am…

微服务架构RabbitMQ实现CQRS模式

在现代软件开发中,微服务架构和CQRS模式都是备受关注的技术趋势。微服务架构通过将应用程序拆分为一系列小型、自治的服务,提供了更好的可伸缩性和灵活性。而CQRS模式则通过将读操作和写操作分离,优化了系统的性能和可维护性。本文小编将为大家介绍如何在ASP.NET Core微服务…

机器学习中的隐马尔可夫模型及Python实现示例

隐马尔可夫模型(HMM)是一种统计模型,用于描述观测序列和隐藏状态序列之间的概率关系。它通常用于生成观测值的底层系统或过程未知或隐藏的情况,因此它被称为“隐马尔可夫模型”。 它用于根据生成数据的潜在隐藏过程来预测未来的观…

第三次面试总结 - 吉云集团 - 全栈开发

🧸欢迎来到dream_ready的博客,📜相信您对专栏 “本人真实面经” 很感兴趣o (ˉ▽ˉ;) 专栏 —— 本人真实面经,更多真实面试经验,中大厂面试总结等您挖掘 目录 总结(非详细) 面试内…

AIGC无人直播系统技术

随着信息技术的快速发展和互联网的普及,直播行业迎来了蓬勃发展的机遇。然而,传统的直播方式存在一些局限性,如场地限制、设备携带不便等问题。为了解决这些问题,AIGC推出了一项创新性的无人直播系统技术。 AIGC无人直播系统技术…

FMEA的定义以及应用目标——SunFMEA软件

故障模式与影响分析(Failure Modes and Effects Analysis,简称FMEA)是一种预防性的质量工具,用于识别和评估产品设计、生产和使用过程中可能出现的故障模式及其对系统性能的影响。通过对故障模式的系统化分析和评估,FM…

​iOS 应用上架指南:资料填写及提交审核

目录 摘要 引言 打开appuploader工具,第二步:打开appuploader工具 第五步:交付应用程序,在iTunes Connect中查看应用程序 总结 摘要 本文提供了iOS新站上架资料填写及提交审核的详细指南,包括创建应用、资料填写-…

震惊!居然有人给 Raspberry Pi 5 做 X 射线!

Jeff Geerling 会做一些莫名其妙的怪事,比如用信鸽来对抗网速,不过这也是我们喜欢他视频的原因。最近,杰夫对 Raspberry Pi 5 进行了 X 光透视,揭示了 Raspberry Pi 5 最新、最强大的计算机内部的秘密。 震惊!居然有人…

软通测试岗面试内部资料

基础性问题 1.你对加班怎么看 2你的优势有哪些 3.你的缺点是什么 4.最有成就感的事情是什么 5.你的职业规划是什么 6离职原因是什么 7.还有什么想问我们的吗 8.你有其他的 offer 吗 专业性问题 9.HTTPS 和 HTTP 的区别 10.HTTPS 的工作原理 11.客户端在使用 HTTPS …

认识Linux指令 “zip/unzip” 指令

01.zip/unzip指令 语法: zip 压缩文件.zip 目录或文件 功能: 将目录或文件压缩成zip格式 常用选项: -r 递归处理,将指定目录下的所有文件和子目录一并处理 举例 将test2目录压缩:zip test2.zip test2/* 解压到…

CUTANA™ pAG-Tn5 for CUTTag

CUTANA pAG-Tn5是靶向剪切及转座酶(CUT&Tag)技术中进行高效绘制染色质特征的关键试剂。与ChIP-seq相比,CUT&Tag在降低细胞需求量和测序深度的信噪比方面进行了显著改进。CUTANA pAG-Tn5是一种高活性的E. coli转座酶突变体(Tn5)与蛋白A/G的融合产物&#xff…

Windows11快速安装Android子系统

很多小伙伴想在电脑运行一下安卓程序,或则上班用手机摸鱼不方便,用电脑又没有想要的手机软件,那么怎么用电脑来安装安卓软件呢? 首先设置地区 安装Android子系统的前提需要安装 Amazon Appstore 这个应用,内地不能下载…

【深入浅出JVM原理及调优】「搭建理论知识框架」全方位带你深入探索类加载机制

全方位带你深入探索类加载机制 专栏介绍前提准备面向人群知识脉络类加载是什么类加载和Class类对象的关系JVM的预加载机制加载class文件的方式 类加载过程(类的生命周期)加载阶段生成对应的Class文件 连接操作验证(确保被加载的类的正确性&am…