您好、欢迎来到现金彩票网!
当前位置:双彩网 > 先行指令站 >

Java JVM(十二):指令重排序

发布时间:2019-06-30 09:33 来源:未知 编辑:admin

  如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性。数据依赖分下列三种类型:

  前面提到过,编译器和处理器可能会对操作做重排序。编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。

  注意,这里所说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。

  as-if-serial语义的意思指:不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守as-if-serial语义。

  为了遵守as-if-serial语义,编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。但是,如果操作之间不存在数据依赖关系,这些操作可能被编译器和处理器重排序。为了具体说明,请看下面计算圆面积的代码示例:

  如上图所示,A和C之间存在数据依赖关系,同时B和C之间也存在数据依赖关系。因此在最终执行的指令序列中,C不能被重排序到A和B的前面(C排到A和B的前面,程序的结果将会被改变)。但A和B之间没有数据依赖关系,编译器和处理器可以重排序A和B之间的执行顺序。下图是该程序的两种执行顺序:

  as-if-serial语义把单线程程序保护了起来,遵守as-if-serial语义的编译器,runtime 和处理器共同为编写单线程程序的程序员创建了一个幻觉:单线程程序是按程序的顺序来执行的。as-if-serial语义使单线程程序员无需担心重排序会干扰他们,也无需担心内存可见性问题。

  这里A happens- before B,但实际执行时B却可以排在A之前执行(看上面的重排序后的执行顺序)。在第一章提到过,如果A happens- before B,JMM并不要求A一定要在B之前执行。JMM仅仅要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前。这里操作A的执行结果不需要对操作B可见;而且重排序操作A和操作B后的执行结果,与操作A和操作B按happens- before顺序执行的结果一致。在这种情况下,JMM会认为这种重排序并不非法(not illegal),JMM允许这种重排序。

  在计算机中,软件技术和硬件技术有一个共同的目标:在不改变程序执行结果的前提下,尽可能的开发并行度。编译器和处理器遵从这一目标,从happens- before的定义我们可以看出,JMM同样遵从这一目标。

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

  flag变量是个标记,用来标识变量a是否已被写入。这里假设有两个线程A和B,A首先执行writer()方法,随后B线程接着执行reader()方法。线时,能否看到线对共享变量a的写入?

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

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

  ※注:本文统一用红色的虚箭线表示错误的读操作,用绿色的虚箭线表示正确的读操作。

  下面再让我们看看,当操作3和操作4重排序时会产生什么效果(借助这个重排序,可以顺便说明控制依赖性)。下面是操作3和操作4重排序后,程序的执行时序图:

  在程序中,操作3和操作4存在控制依赖关系。当代码中存在控制依赖性时,会影响指令序列执行的并行度。为此,编译器和处理器会采用猜测(Speculation)执行来克服控制相关性对并行度的影响。以处理器的猜测执行为例,执行线程B的处理器可以提前读取并计算a*a,然后把计算结果临时保存到一个名为重排序缓冲(reorder buffer ROB)的硬件缓存中。当接下来操作3的条件判断为真时,就把该计算结果写入变量i中。

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

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

  什么是指令重排序?有两个层面:**在虚拟机层面,**为了尽可能减少内存操作速度远慢于CPU运行速度所带来的CPU空置的影响,虚拟机会按照自己的一些规则(这规则后面再叙述)将程序编写顺序打乱——即写在后...博文来自:chao430的博客

  指令重排序有两类,编译器重排序和处理器重排序。编译器重排序发生在编译期,处理器重排序发生在运行时。其实指令重排序的本意是提高程序并发效率,原则是重排序后的程序运行结果和单线程运行结果一致。为什么指令重...博文来自:wAitonly的博客

  背景问题出现在6360灰度期间从Crash平台上看到了一个NullPointerException,虽然量不大,但是很怪异,大致长这个样子这是个什么空指针?居然说我LinkedList.iterato...博文来自:的博客

  一,编译器指令重排序编译器在不影响程序执行的结果下,可能对代码执行的先后顺序进行调整;如:以下代码第二条可能会比第一条先执行;inta=1; //&1intb=2;//& 2以下代码会顺序执行,不会改...博文来自:mikejaps的博客

  为了使得处理器内部的运算单元能尽量被充分利用,处理器可能会对输入的代码进行乱序执行优化,处理器会在计算之后将乱序执行的结果重组,保证该结果与顺序执行的结果是一致的,但并不保证程序中的各个语句计算的先后...博文来自:xuqiaobo的博客

  字节码简介1.计算机只能识别01,经过01的组合,产生了数字 ,01组合也产生了各种字符,各种机器指令2.不同的时代,不同产商,机器指令集(arm,x86,rsic...)是不同的3.CPU与指令集直...博文来自:的博客

  内存间交互操作lock:作用主内存unlock:作用主内存read/load:这两个操作顺序执行,不能单独出现;主内存的变量=gt;工作内存的变量use:作用工作内存,把工作内存变量传给执行...博文来自:吃货先生的博客

  重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。但是不能随时随地的重排序,我们可以看一个例子看待这个问题。上面三种情况,只要重排序两个操作的执行顺序,那么程序的结果就会被改...博文来自:yanghan1222的博客

  在JMM(Java内存模型)中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。happens-before原则规则:程序次序规则:一个线程内,...博文来自:的博客

  重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境。特别是多个线程同时修改同一变量时,必须采...博文来自:kingzma的专栏

  我们知道java在运行的时候有两个地方可能会把指令重排序,一个是编译器编译的的时候,一个是处理器运行的时候。那么为啥要用指令重排序呢?编译期重排序有啥好处?CPU计算的时候要访问值,如果常常利用到寄存...博文来自:nO0b

  JVM学习之路(一)——java程序执行流程JVM学习之路(二)——JVM的内部结构JVM学习之路(三)——JVM内部结构详细介绍及其相互作用JVM学习之路(四)——内存模型(java多线程通信)JV...博文来自:u012556994的博客

  volatile的有序性是使用内存屏障实现的,它能禁止指令重排序。在执行程序时为了提高性能,编译器和处理器通常会对指令做重排序:编译器重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执...博文来自:乔治de博客

  指令重排序对主存的一次访问一般花费硬件的数百次时钟周期。处理器通过缓存(caching)能够从数量级上降低内存延迟的成本这些缓存为了性能重新排列待定内存操作的顺序。也就是说,程序的读写操作不一定会按照...博文来自:shuhuai007的专栏

  引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序;在特定情况下,指令重排将会给我们的程序带来不确定的结果.......博文来自:木小鱼的笔记

  重排序重排序是编译器和处理器为了优化性能而对指令执行的顺序进行重排序。大多数现代处理器都会采用将指令乱序执行的方法,在条件允许的情况下,直接运行当前有能力立即执行的后续指令,避开获取下一条指令所需数据...博文来自:夫子与歌的博客

  上一次的发文远在两个月前了,算是经历了一段低糜期,本来打算的更新一直断更到现在。还是好好学习吧,努力的人运气一定不会差的。这一篇文章来谈一谈Java虚拟机对代码优化带来的影响吧。我们知道无论什么语言,...

  为什么有重排序?执行程序时,为了提高性能,处理器和编译器常常会对指令进行重排序。我们常将的重排序包括处理器重排序和编译器重排序。 重排序需要满足的条件①在单线程环境下不能改变程序运行的结果;②存在数据...

  重排序 在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序。重排序分3种类型。1)编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。2)指令级并行的重排...

  引言大家都知道volatile关键字具有两重语义即:1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线)禁止进行指令重排序。第一个好理解...

  前言在前几章中,我们介绍了线程安全相关的关键字synchronized与volatile的使用,在介绍其原理的过程中,我们提及到了Java中的“happen-before”规则,这个规则对于我们理解J...

  1、内存可见性首先,要明确一下这个内存的含义,内存包括共享主存和高速缓存,Volatile关键字标识的变量,是指CPU从缓存读取数据时,要判断数据是否有效,如果缓存没有数据,则再从主存读取,主存就不存...

  一、原子性原子性操作指相应的操作是单一不可分割的操作。例如,对int变量count执行count++d操作就不是原子性操作。因为count++实际上可以分解为3个操作:(1)读取变量count的当前值...

  什么是重排序什么是内存可见性将产生的问题如何解决问题什么是重排序重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种优化措施如果两个操作访问同一个变量,且这两个操作有一个为写操作,此...

  在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序。重排序会遵守数据的依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。重排序分为如下三种类型。编译器优化的重排序。编译...

  理解一下数据依赖性  如果有两个操作,访问同一个变量并且有一个操作是写操作,那这两个操作存在数据依赖。  一般有如下几种情况:   1.写后写:a=1;a=2;   2.写后读:a=1;b=a;   ...

  重排序在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序重排序有三种类型:1.编译器优化的重排序编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序2.指令级并行的重排序现代处理...

  hashmap从jdk1.2开始加入,从经典的1.6开始吧。hashmap的底层是数组,容量始终是2的倍数2^n,初始容量?自动扩容*2。数组中每个元素作为一个哈希桶,什么是哈希桶?不同的key可能会...

  为了提高程序的执行性能,编译器和处理器常常会对指令做重排序。有以下三种类型:1、编译器优化的重排序2、指令级并行的重排序3、内存重排序...

  最近在看《Java并发编程的艺术》,看到双重检查锁定里谈到用volatile来解决创建对象时,指令重排序的问题,想了解清楚为什么volatile可以禁止指令重排序,结果得到了出乎意料的答案。...

  Java基础知识指令重排序在执行程序时,为了提高性能,编译器和处理器会对指令做重排序。编译器优化重排序:编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。指令级并行的重排序:如果不存l...

  内存屏障是一个很神奇的东西,之前翻译了Linux内核文档memory-barriers.txt,对内存屏障有了一定有理解。现在用自己的方式来整理一下。在我看来,内存屏障主要解决了两个问题:单处理器下的...

  流水线是一种指令级并行技术。指令执行步骤取指 IF                (从内存中取出指令)          译码和取寄存器操作数 ID  (把指令送到指令译码器进行译码,产生相应控制信号...

  1、首先为何要指令重排序(instructionreordering)?编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。也就是说,对于下面两条语句:inta=10;intb...

  前言在我们编写程序并运行的时候,编译器给我们一个错觉:程序编译的顺序与编写的顺序是一致的。但是实际上,为了提高性能,编译器和处理器常常会对指令进行重排序。重排序主要分为两类:编译器优化的重排序、指令级...

  本篇文章是根据我的上篇博客,给出的改进版,由于时间有限,仅做了一个简单的优化。相关文章:将excel导入数据库2018年4月1日,新增下载地址链接:点击打开源码下载地址十分抱歉,这个链接地址没有在这篇...

  最近比较有空,大四出来实习几个月了,作为实习狗的我,被叫去研究Docker了,汗汗! Docker的三大核心概念:镜像、容器、仓库 镜像:类似虚拟机的镜像、用俗话说就是安装文件。 容器:类似一个轻量...

  前言:前段时间做项目用到了图片裁剪,调用系统裁剪图片,结果在我的小米3上一直有问题,裁剪界面打不开,在其他设备上没问题,于是研究其他软件是怎么做的,淘宝的裁剪图片是自己做的,当然没问题,京东的是调用的...

  zwenkaiIntellij IDEA 如何通过数据库表生成带注解的实体类图文详细教程

  Intellij IDEA 如何通过数据库表生成带注解的实体类图文详细教程 Intellij IDEA 如何通过数据库表生成带注解的实体类 Contents 第一步:新建...

  灰度图像的自动阈值分割(Otsu 法)机器视觉领域许多算法都要求先对图像进行二值化。这种二值化操作阈值的选取非常重要。阈值选取的不合适,可能得到的结果就毫无用处。今天就来讲讲一种自动计算阈值的方法。这...

  用以前以前写过的自定义课表软件 ,Android 自定义View课程表表格 原生View截图合成分享的图片 看到的是图片只显示到11节处,下面的没有...

  本matplotlib安装过程在一定程度上参考了 因为学习机器学习的需要,又准备参考《机器学...

  servlet页面代码:@每次请求时产生一个token(一般为时间戳),存于session中并随之用hidden提交,在servlet中判断接收到的token和session中的是否一致来判断是否重复...

  首先,确定你已经有了CSR证书请求、开发证书和App ID。如果你不是第一次开发iOS应用程序,那么你可能已经有了这些东西。那么你可以继续以下的步骤。一、配置App ID登录你的provisionin...

  目前还没有写出这个demo,不过可以参考下面这两个链接,一个是显示日期的,还有一个是合并单元格: 合并单元格:

  以回归为例吧,回归在某些场合可能更精准 支持连续变量和类别变量,类别变量就是某个属性有三个值,a,b,c,需要用Feature Transformers中的vectorindexer处理 上来是一堆...

  扫二维码关注,获取更多技术分享 本文承接之前发布的博客《 微信支付V3微信公众号支付PHP教程/thinkPHP5公众号支付》必须阅读上篇文章后才可以阅读这篇文章。由于最近一段时间工作比较忙,...

  强连通分量: 简言之 就是找环(每条边只走一次,两两可达) 孤立的一个点也是一个连通分量   使用tarjan算法 在嵌套的多个环中优先得到最大环( 最小环就是每个孤立点)   定义: int Ti...

  jquery/js实现一个网页同时调用多个倒计时(最新的) 最近需要网页添加多个倒计时. 查阅网络,基本上都是千遍一律的不好用. 自己按需写了个.希望对大家有用. 有用请赞一个哦! //js ...

  简述关于gif的使用在实际项目中我用的并不多,因为我感觉瑕疵挺多的,很多时候锯齿比较严重,当然与图存在很大的关系。关于生成gif的方法可以提供一个网站preloaders,基本是可以满足需求的。简述 ...

  本博客暂停更新,后期专注维护个人公众号『高效程序员』,欢迎关注!python版本DDOS攻击脚本

  今天为了休息下,换换脑子,于是就找到了我之前收藏的一篇python的文章,是关于ddos攻击的一个脚本,正好今天有空,就实践下了。 附上源码pyDdos.py: #!/usr/bin/env ...

http://deafbook.net/xianxingzhilingzhan/241.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有