Java 指令重排

Java 指令重排

java 指令重排


package com.feshfans;

/**
 * 用来演示指令重排
 * 指令重排会发生在两个阶段:
 * 1. 编译期(jvm 加载字节码时)
 * 2. cpu 执行期
 * 但对于单线程来说,不管发生怎样的重排,都必须保持与源代码一致的输出结果(As-If-Serial).
 * 上述规则保证了单线程的执行结果总是与预期一致,但在多线程的情况,就会出现与预期不一致的情况,
 * 而导致这一情况发生的原因,正是指令重排
 *
 */
public class InstructionReOrder {

    static Integer a = 0;
    static Integer b = 0;
    static Integer x = 0;
    static Integer y = 0;

    private void showReOrder() throws InterruptedException {

        for(int i=0;i<Integer.MAX_VALUE;i++){
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    // 有可能发生重排,即 先执行 x = b,再执行 a = 1
                    a = 1;
                    x = b;

                }
            });

            Thread t2= new Thread(new Runnable() {
                @Override
                public void run() {
                    // 有可能发生重排,即先执行 y = a,再执行 b = 1;
                    b = 1;
                    y = a;
                }
            });

            t1.start();
            t2.start();
            t1.join();
            t2.join();
            /**
             * 如果没有指令重排,输出的可以结果为:(0,1)(1,1)(1,0)
             * 但实际上有可能会输出(0,0)
             */
            System.out.println("第 "+ i + "次,x="+x +", y="+y);
            if(x == 0 && y == 0){
                break;
            }
            a = b = 0;
            x = y = 0;
        }
    }

    public static void main(String[] args) {
        InstructionReOrder reOrder = new InstructionReOrder();
        try {
            reOrder.showReOrder();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

输出结果如下:

指令重排输出结果

从上图中可以看出,执行到第 65456 次时,发生了指令重排

原文地址:https://www.cnblogs.com/feshfans/p/11272757.html

时间: 2024-11-08 10:44:19

Java 指令重排的相关文章

Java并发编程(五)JVM指令重排

引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序:在特定情况下,指令重排将会给我们的程序带来不确定的结果..... 如下代码可能的结果有哪些? public class PossibleReordering { static int x = 0, y = 0; static int a = 0, b = 0; public static void main(String[] args) throws InterruptedException {

Java中指令重排

/** * 指令重排:代码执行顺序与预期不一致 (发生在前后行代码无联系时) * 目的:提高性能 * */ public class HappenBefore { private static int a=0; private static boolean flag=false; public static void main(String[] args) throws InterruptedException { for(int i=0;i<10;i++) { a=0; flag=false;

jvm 指令重排

引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序:在特定情况下,指令重排将会给我们的程序带来不确定的结果..... 1.  什么是指令重排? 在计算机执行指令的顺序在经过程序编译器编译之后形成的指令序列,一般而言,这个指令序列是会输出确定的结果:以确保每一次的执行都有确定的结果.但是,一般情况下,CPU和编译器为了提升程序执行的效率,会按照一定的规则允许进行指令优化,在某些情况下,这种优化会带来一些执行的逻辑问题,主要的原因是代码逻辑之间是存在一

轻量级的同步机制——volatile语义详解(可见性保证+禁止指令重排)

1.关于volatile volatile是java语言中的关键字,用来修饰会被多线程访问的共享变量,是JVM提供的轻量级的同步机制,相比同步代码块或者重入锁有更好的性能.它主要有两重语义,一是保证多个线程对共享变量访问的可见性,二防止指令重排序. 2.语义一:内存可见性 2.1 一个例子 public class TestVolatile { public static void main(String[] args) throws InterruptedException { ThreadD

volatile关键字?MESI协议?指令重排?内存屏障?这都是啥玩意

一.摘要 三级缓存,MESI缓存一致性协议,指令重排,内存屏障,JMM,volatile.单拿一个出来,想必大家对这些概念应该有一定了解.但是这些东西有什么必然的联系,或者他们之间究竟有什么前世今生想必是困扰大家的一个问题.为什么有了MESI协议,我们还需要volatile?内存屏障的由来?指令重排带来的问题?下面我们通过分析每一个技术的由来,以及带来的负面影响,跟大家探讨一下这些技术之间的联系.具体每个关键词相关文章也很多不再赘述,只谈个人理解. 二.三级缓存篇 1,三级缓存的由来 CPU的发

为什么synchronized无法禁止指令重排,却能保证有序性

为了进一步提升计算机各方面能力,在硬件层面做了很多优化,如处理器优化和指令重排等,但是这些技术的引入就会导致有序性问题. 先告诉面试官你知道什么是有序性问题,也知道是什么原因导致的有序性问题 我们也知道,最好的解决有序性问题的办法,就是禁止处理器优化和指令重排,就像volatile中使用内存屏障一样. 表明你知道啥是指令重排,也知道他的实现原理 但是,虽然很多硬件都会为了优化做一些重排,但是在Java中,不管怎么排序,都不能影响单线程程序的执行结果.这就是as-if-serial语义,所有硬件优

JVM指令重排

指令重排的基本原则: a.程序顺序原则:一个线程内保证语义的串行性 b.volatile规则:volatile变量的写,先发生于读 c.锁规则:解锁(unlock)必然发生在随后的加锁(lock)前 d.传递性:A先于B,B先于C 那么A必然先于C e.线程的start方法先于它的每一个动作 f.线程的所有操作先于线程的终结(Thread.join()) g.线程的中断(interrupt())先于被中断线程的代码 h.对象的构造函数执行结束先于finalize()方法 写后读 a = 1;b

JVM学习--数字存储,内存模型,指令重排

一.数字在计算机中如何存储 整数:以补码形式存储. 补码:正数的补码是自身,负数的补码是取反码加1(取反码时符号位还是1) 浮点型:以float类型表示   注意一下,这八位指数实际上是(127+次数)的结果,因为要考虑到负数指数的情况,例如如下120.5在计算机中的存储: 而因为科学计数法第一位总是1开头,可以将小数点前面的1省略,所以23bit的尾数部分,可以表示的精度却变成了24bit.那24bit能精确到小数点后几位呢,我们知道9的二进制表示为1001,所以4bit能精确十进制中的1位小

eclipse使用步骤,javac和java指令的区别

javac指令和 java指令: javac负责 将源文件编译成 字节码文件 (.class) , 编译时要指明 .java后缀,不能省略 java指令 负责 将 字节码文件 转为 机器码, 对其进行运行, java指令后的 字节码文件 省略 .class后缀 直接操作 javac 对源文件进行编译的弊端: 每对源文件进行修改, 都需要重新对其编译, 才能 运行产生 更改后的效果 解决方案: 使用 集成开发工具 eclipse : 免费, IBM提供 , 普及率比较高 Myeclipse:收费