首页
学习
活动
专区
圈层
工具
发布
    • 综合排序
    • 最热优先
    • 最新优先
    时间不限
  • 来自专栏全栈程序员必看

    jvm之指令重排_java指令重排

    引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序;在特定情况下,指令重排将会给我们的程序带来不确定的结果….. 1. 什么是指令重排? 在计算机执行指令的顺序在经过程序编译器编译之后形成的指令序列,一般而言,这个指令序列是会输出确定的结果;以确保每一次的执行都有确定的结果。 在多线程下的指令重排 首先我们基于一段代码的示例来分析,在多线程情况下,重排是否有不同结果信息: [html] view plain copy print ? 指令重排的原因分析 主要还是编译器以及CPU为了优化代码或者执行的效率而执行的优化操作;应用条件是单线程场景下,对于并发多线程场景下,指令重排会产生不确定的执行效果。 6. volatile还有一个作用就是局部阻止重排序的发生,对volatile变量的操作指令都不会被重排序,因为如果重排序,又可能产生可见性问题。

    49420编辑于 2022-09-27
  • 来自专栏全栈程序员必看

    指令重排详解_cpu指令重排

    指令重排: 编译器指令重排,cpu指令重排,内存指令重排。 编译器可能会调整顺序,如下图,左边是c++源码,右边是优化后顺序 一条汇编指令的执行是可以分为很多步骤的, 分为不同的硬件执行 取指 IF 译码和取寄存器操作数 ID 执行或者有效地址计算 EX (ALU逻辑计算单元) 存储器访问 MEM 写回 WB (寄存器) 指令重排只可能发生在毫无关系的指令之间, 如果指令之间存在依赖关系, 则不会重排。 2 有序性是指在单线程环境中, 程序是按序依次执行的,而在多线程环境中, 程序的执行可能因为指令重排而出现乱序。

    1.1K80编辑于 2022-11-02
  • 来自专栏全栈程序员必看

    线程指令重排

    1、指令重排 JVM为优化执行效率对线程内的执行顺序进行重排,对单线程来说执行指令重排并不会影响程序从上到下执行的代码逻辑。但是在多线程的情况下,则可能会出现问题。 2、指令重排原则 程序顺序原则:一个线程内保证语义的串行性 volatile规则:volatile变量的写,先发生于读 锁规则:解锁(unlock)必然发生在随后的加锁(lock)前 传递性:A先于 Override public void run() { order.read(); }}); threadA.start(); threadB.start(); } } 4、避免指令重排 指令重排是编译器的一种优化手段,但是在多线程中可能会影响到代码逻辑。 如何避免指令重排可以通过同步的方式(性能问题) package com.thread.study; public class OrderExample { int a = 0; boolean

    47050编辑于 2022-11-02
  • 来自专栏网络收集

    指令重排

    指令重排序只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码逻辑顺序不一致,这个过程就叫做指令重排序。 指令重排序的意义:使指令更加符合 CPU 的执行特性,最大限度的发挥机器的性能,提高程序的执行效率。指令重排序分类指令重排序主要分为三种,在这里主要讨论 JVM 中的指令重排序。 编译器重排序:JVM 中完成指令级并行重排序处理器重排序:CPU 中完成指令重排序原则如果程序中操作A在操作B之前,那么线程中操作A将在操作B之前执行。 (只对指令内部重排序,不在指令重排序)As-If-Serial语义不管怎么进行指令重排序,单线程内程序的执行结果不能被改变。编译器和处理器对存在依赖关系的操作都不会对其进行重排序。 (如果线程1解锁了monitor a,接着线程2锁定了a,那么,线程1解锁a之前的写操作都对线程2可见(线程1和线程2可以是同一个线程))防止指令重排序volatile关键字通过“内存屏障”来防止指令重排

    58830编辑于 2022-08-07
  • 来自专栏全栈程序员必看

    volatile指令重排

    什么时候会发生指令重排? 先来一个测试指令重排现象,下面这段代码会发生指令重排,也就是JVM优化了执行顺序。 /** * 指令重排测试 */ public class CommandDisorder { // 当使用volatile关键词修饰变量时,则不会出现指令重排现象 private static /* ", i)); break; } else { System.out.println(i); } } } } 指令重排,异常出现了: 什么是指令重排? 为了提高性能,编译器和处理器常常会对既定的代码执行顺序进行指令重排序,JMM内部会有指令重排,并且会有af-if-serial和happen-before的理念来保证指令的正确性。 真实的业务中如何避免指令重排? 在真实业务场景中,预测到可能有多线程访问同一个变量时,建议加上volatile关键词,保证变量在线程间的可见性。 举一个简单的例子,单例模式。

    89220编辑于 2022-11-07
  • 来自专栏韩曙亮的移动开发专栏

    【Java 并发编程】线程指令重排序问题 ( 指令重排序规范 | volatile 关键字禁止指令重排序 )

    文章目录 总结 一、指令重排序规范 二、指令重排序示例 总结 Java 并发的 3 特性 : 原子性 : 每个操作都是 不可拆分的原子操作 ; 在线程中进行 a++ 就不是原子操作 , 该操作分为 " ; 保证 有序性 ; 一、指令重排序规范 ---- 指令重排指的是 , 线程中如果两行代码 没有逻辑上的上下关系 , 可以对代码进行 重新排序 ; JVM 指令重排遵循规范 : as-if-serial 规范 : 单个线程中, 指令重排 , 不能影响程序的执行结果 ; 可以重排的情况 : 对于下面代码 , 两条指令顺序颠倒 , 执行结果相同 , 可以进行指令重排 ; x = 0; y = 1; 不可以进行重排的情况 : 对于下面的代码 , 两条指令如果上下颠倒 , 结果不同 , 不可以进行指令重排 ; x = 0; y = x; happens-before 规范 : 先行发生原则 ; 二、指令重排序示例 --- - 指令重排示例 : public class Main { // 使用 volatile 关键字修饰变量可以禁止指令重排 /*volatile static int x = 0;

    1.7K30编辑于 2023-03-29
  • 来自专栏从码农的全世界路过

    指令重排与内存屏障

    指令重排是编译器或者CPU为了优化代码执行效率, 减少CPU的执行时钟周期而进行的优化操作; 这只是CPU众多优化的一种. 在单线程条件下,不会改变程序执行结果; 对于多线程并发情况下, 指令重排可能会产生不确定的执行结果. As-If-Serial 先看一个指令重排例子: 源代码如下: Int a = 1; Int b = 2; Int c = a + b; 这里 a 和b 的初始化, 就可能出现重排, 执行顺序变为: Int 为什么c的计算语句不会重排么, 这是因为单线程情况下, 指令重排要遵守As-If-Serial语义, 编译器和处理器不会对存在数据依赖关系的操作做重排. 将内存地址赋值给指针obj; 由于CPU的指令重排, 步骤2 和步骤3 很有可能出现颠倒执行, 已经将地址赋值给了obj, 但还没有实例化. 这时有其他线程使用obj实例时, 就会出现空指针异常.

    74910编辑于 2022-06-20
  • 来自专栏全栈程序员必看

    Cpu指令重排_cpu的指令

    Cpu为了提高效率会对指令进行重排序,以适合cpu的顺序运行。 但是指令重排会遵守As-if-serial的规则,就是所有的动作(Action)都可以为了优化而被重排序,但是必须保证它们重排序后的结果和程序代码本身的应有结果是一致的。 是一种屏障指令,cpu指令。Java中的实现方式就是使用volatile关键字,既可以解决可见性,又可以禁止指令重排。 而java层的屏障有四种,分别是上面两种的组合,分别是: LoadLoad屏障: 抽象场景:Load1; LoadLoad; Load2 Load1 和 Load2 代表两条读取指令。 StoreStore屏障: 抽象场景:Store1; StoreStore; Store2 Store1 和 Store2代表两条写入指令

    937150编辑于 2022-11-02
  • 来自专栏xdecode

    Java内存模型与指令重排

    CPU指令重排 编译器优化重排 Happen-Before规则 原子性 原子性是指一个操作是不可中断的. 会有多种场景影响到可见性: CPU指令重排 多条汇编指令执行时, 考虑性能因素, 会导致执行乱序, 下文会有详细讲述. 指令重排 指令重排是指在程序执行过程中, 为了性能考虑, 编译器和CPU可能会对指令重新排序. 经过指令重排后, 整个流水线会更加顺畅, 无气泡阻塞执行. ? 原先需要14个时钟周期的指令, 重排后, 只需要12个时钟周期即可执行完毕. 指令重排只可能发生在毫无关系的指令之间, 如果指令之间存在依赖关系, 则不会重排. 如 指令1 : a = 1 指令2: b = a - 1, 则指令1, 2 不会发生重排.

    1.9K50发布于 2018-05-28
  • 来自专栏大数据那些事

    指令重排与jvm底层实现

    指令重排涉及到如下四种,loadload,loadstore,storeload,storestore,在jvm里只会涉及到storeload,只有这一种才会导致你的程序不稳定,截一张jvm底层代码的图 在x86平台下,用如下方法实现不让指令重排的操作: ? 在x86情况下,指令屏障只会用在storeload上,其他的只需要告诉在编译阶段不要把指令重新排序即可。 ?

    50710发布于 2021-06-17
  • 来自专栏艾小仙

    什么是指令重排序呢?

    什么是指令重排序呢? 为了更加直观地理解,笔者还是通过一个案例来说明。 其实这就是所谓的指令重排序问题,假设上面的代码通过指令重排序之后,变成下面这种结构: Thread t1=new Thread(()->{ x=b; //指令重排序 a=1; }); Thread 01.什么是指令重排指令重排序是指编译器或CPU为了优化程序的执行性能而对指令进行重新排序的一种手段,重排序会带来可见性问题,所以在多线程开发中必须要关注并规避重排序。 并行指令重排序,这是处理器优化的一种,处理器可以改变指令的执行顺序。 内存系统重排序,这是处理器引入Store Buffer缓冲区延时写入产生的指令执行顺序不一致的问题,在后续内容中会详细说明。 那么什么是并行指令集的重排序呢? 如下图所示,假设某一段程序有多条指令,不同指令的执行实现也不同。

    1.1K10编辑于 2021-12-08
  • 来自专栏MageekChiu

    为什么要指令重排序?

    我们知道java在运行的时候有两个地方可能用到重排序,一个是编译器编译的的时候,一个是处理器运行的时候。 那么我们就应该问问为啥要用指令重排序呢? 分析 编译期重排序有啥好处? 处理器为啥要重排序? 因为一个汇编指令也会涉及到很多步骤,每个步骤可能会用到不同的寄存器,CPU使用了流水线技术,也就是说,CPU有多个功能单元(如获取、解码、运算和结果),一条指令也分为多个单元,那么第一条指令执行还没完毕 ,就可以执行第二条指令,前提是这两条指令功能单元相同或类似,所以一般可以通过指令重排使得具有相似功能单元的指令接连执行来减少流水线中断的情况。

    1.3K50发布于 2018-05-25
  • 来自专栏后台公论

    指令重排序与内存屏障

    而这其中的原因呢,就要引出今天我们的议题了:编译器和CPU会对指令进行重排序! 好了,开始讲讲什么是指令重排序,什么是内存屏障吧! 指令重排序 编译器为了提高程序的性能,有时不会按照程序代码对应的指令顺序来执行,而是乱序执行(Out-of-order execution)。 当然不仅编译器,CPU也会对程序进行优化,从而导致指令重排。 此外前面我有提到,编译器和CPU都会导致指令重排序。 它能直接保证前面三种屏障,也就是说不需要去写汇编指令去阻止CPU对前面三种类型读写操作的重排。但x86 CPU无法保证StoreLoad类型的屏障。

    77830编辑于 2021-12-08
  • 来自专栏全栈程序员必看

    volatile禁止指令重排序_volatile int

    volatile禁止指令重排 JMM要求有序性 计算机在执行程序时,为了提高性能,编译器和处理器常常会做指令重排,一把分为以下3种 单线程环境里面确保程序最终执行结果和代码顺序执行的结果一致. (单线程不用关心指令重排) 处理器在进行重新排序是必须要考虑指令之间的数据依赖性 多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程使用的变量能否保持一致性是无法确定的,结果无法预测 源码写的顺序不见得和编译的指令顺序一样 答:存在数据的依赖性 ,语句4 没办法排到第一个 正常情况下指令重排,不是每次指令都会重排 例子2 int a ,b ,x,y=0; 线程1 线程2 x=a; y=b; b=1; a=2; 结果 :x ,执行了if条件体内的命令,a成为5 就会和不指令重排的结果(6)不一致。 所以指令重排会造成值不一致,所以有时候我们需要 volatile禁止指令指令重排 总结(了解) PS:学习笔记,资源:尚硅谷,周阳 版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。

    55640编辑于 2022-11-02
  • 来自专栏程序员小灰

    漫画:volatile对指令重排的影响

    什么是指令重排指令重排是指JVM在编译Java代码的时候,或者CPU在执行JVM字节码的时候,对现有的指令顺序进行重新排序。 指令重排的目的是为了在不改变程序执行结果的前提下,优化程序的运行效率。 然而,指令重排是一把双刃剑,虽然优化了程序的执行效率,但是在某些情况下,会影响到多线程的执行结果。 需要注意的是,这里java代码的重排只是为了简单示意,真正的指令重排是在字节码指令的层面。 什么是内存屏障? 编译时JVM编译器遵循内存屏障的约束,运行时依靠CPU屏障指令来阻止重排。 几点补充: 1. 我们这里只简单列出了其中一种,有兴趣的同学可以查资料进一步学习其他阻止指令重排的场景。 2.volatile除了保证可见性和阻止指令重排,还解决了long类型和double类型数据的8字节赋值问题。

    48820编辑于 2022-07-05
  • 来自专栏钟绍威的专栏

    从源代码到Runtime发生的重排序编译器重排指令重排序内存系统重排序阻止重排

    2; int a1 = x * 1; int a2 = x * 2; int a3 = x * 3; int b1 = y * 1; int b2 = y * 2; int b3 = y * 3; 指令重排序  指令重排序是处理器层面做的优化。 看看有没有能优先执行的指令,操作2依赖于操作1,不能被优先执行,操作3不依赖1和2,所以能优先执行操作3。 阻止重排序  不论哪种重排序都可能造成共享变量中线程间不可见,这会改变程序运行结果。所以需要禁止对那些要求可见的共享变量重排序。 阻止编译重排序:禁止编译器在某些时候重排序。 阻止指令重排序和内存系统重排序:使用内存屏障或Lock前缀指令

    1.6K90发布于 2018-02-05
  • 来自专栏软件工程

    Java发生指令重排的几个地方

    一.指定重排的原则 编译器和处理器不是胡乱的重排序的,他们会遵循一个关键的规则,就是数据依赖规则,如果说一个变量的结果依赖于之前的代码执行结果,那么就不能随意进行重排序,要遵循数据的依赖。 二.指定重排的位置 2.1 编译时 编译后的代码的执行顺序:java里有两种编译器,一个是静态编译器(javac),一个是动态编译器(JIT)。 2.2 处理器执行时候 即使我们给处理器一个代码的执行顺序,处理器也可能会重排代码,更换一种执行顺序。 2.3 内存重排序 有可能一个处理器在实际执行的过程中,在写缓冲器,高速缓存等等一些硬件也能导致指令执行顺序和我们想象的不一样。 如图所示,画红圈的都是可能发生指定重排的地方

    84540编辑于 2021-12-24
  • 来自专栏JavaBuild888

    关于volatile与指令重排序的探讨

    写在开头 在之前的学习我们了解到,为了充分利用缓存,提高程序的执行速度,编译器在底层执行的时候,会进行指令重排序的优化操作,但这种优化,在有些时候会带来 有序性 的问题。 那何为有序性呢? 那么今天,我们继续学习,一起探讨一下volatile与指令重排之间的冤家路窄! 有序性问题 首先,我们来回顾一下之前写的一个关于有序性问题的测试类。 但有些时候,指令重排序可以保证串行语义一致,但是没有义务保证多线程间的语义也一致,我们继续看下面这段代码: 【代码示例2】 public class Test { private static 原因解析 volatile关键字可以禁止指令重排的原因主要有两个! 二、内存屏障 变量声明为 volatile 后,在对这个变量进行读写操作的时候,会通过插入特定的 内存屏障 的方式来禁止指令重排序。

    30500编辑于 2024-05-27
  • 来自专栏蝉沐风的码场

    CPU流水线与指令重排

    当然,本文说的优化主要是指令重排(Compiler Reordering)。 编译器必须遵守as-if-serial语义,也就是编译器不会对存在数据依赖关系的操作做重排序,因为这种重排序会改变执行结果。 但是,如果操作之间不存在数据依赖关系,这些操作就可能被编译器和处理器重排序。 我们用非常简单的C++代码举个例子(因为编译更简单,看起来也更直观)。 既然汇编指令重排了,CPU的执行顺序自然是根据汇编指令对应的机器指令执行的,大概率也会被重排。其实除此之外,CPU本身也会对指令进行重排(CPU Reordering)。 2. 回到本文一开始说的编译器指令重排序,当然喽,也包含Java的JIT将字节码编译成机器码时的指令重排序,就是为了把没有依赖关系的指令放一起,本质上都是为了适配CPU,更好地发挥出CPU流水线的功能,从而提升性能罢了

    1.4K20编辑于 2022-12-19
  • 来自专栏小明说Java

    从Java里认识汇编指令重排

    前言 编译器重排指令主要是为了优化程序的执行效率。编译器会根据程序的语义和指令的特性,对指令进行重新排序,使得程序在执行时能够更快地完成。 例如,编译器可能会将循环中的计算指令重新排序,以避免CPU缓存的缺失,从而提高程序的执行速度。编译器和处理器常常会对指令重排,保证每个指令都在寄存器中可以获取,一般分为一下3种 1. 指令重排(Instruction Scheduling):编译器和处理器可以对指令进行重新排序,以优化程序的执行效率。 三、禁止指令重排 在Java中,可以通过将变量声明为`volatile`或使用`synchronized`关键字来禁止指令重排。 1. 使用volatile关键字 将变量声明为`volatile`可以禁止指令重排

    64770编辑于 2023-11-01
领券