证明程序会发生指令重排

我们应用程序的执行,是通过cpu执行各种不同的指令完成的。cpu的速度是比内存要快100倍以上,先看一张图。

证明程序会发生指令重排_第1张图片

因此当cpu从内存load两条不相关的指令时,比如,第一条指令需要向内存写数据,第二条指令只需要在cpu寄存器执行操作就行了,这个时候,因为cpu的优化机制,就会先执行第二条指令,这就是所谓的指令重排

那么,怎么证明呢?这里用了数学中的反证法,直接上代码!

package com.tml.mouseDemo.core.jvm;


public class DisOrder {
    static int a;
    static int b;
    static int y;
    static int x;


    public static void main(String[] args) throws InterruptedException {
        int count = 0;
        while (true) {
            a = 0;
            b = 0;
            y = 0;
            x = 0;

            Thread t1 = new Thread(() -> {
                a = 1;
                x = b;
            });

            Thread t2 = new Thread(() -> {
                b = 1;
                y = a;
            });

            t1.start();
            t2.start();

            t1.join();
            t2.join();

            count++;

            if (x == 0 && y == 0) {
                System.out.println("程序发生了指令重排,第" + count + "次");
                break;
            }
        }
    }
}

程序很简单,定义了四个静态变量abxy,然后在一个死循环中两个线程分别对这四个变量进行赋值。

假如程序不会发生指令重排,那么a = 1;  一定先于  x = b; 执行,b = 1; 一定先于 y = a; 执行,那么两个线程并发执行的排列组合就是C(4,2)=6

组合的公式参考

证明程序会发生指令重排_第2张图片

 这6种组合后,程序的执行结果应该是这样:

证明程序会发生指令重排_第3张图片

可以看到,在假设程序不存在指令重排的基础上,那么xy的结果是不可能出现均为0的情况的。

反证法执行程序后的结果【这个程序执行的次数要看运气,因为多线程本来就是一个随机的事情】

证明程序会发生指令重排_第4张图片

反证的结果与事实不符,假设不成立。也就是,在高级语言中会发生指令重排,这里不仅仅是java会发生,其他高级语言也会发生指令重排。

因为指令重排导致的bug很不好发现,需要有足够的并发冲击才会出现,但是一旦出现,就会造成重大的数据问题。在java中,解决此问题就是使用volatile关键字,禁止重排。

你可能感兴趣的:(java,多线程,java,开发语言)