证明:Java代码在执行过程中,并不一定是从上到下,每句代码依次顺序执行的

今天给大家带来一个毁三观的结论:Java代码在执行过程中,并不一定是从上到下,每句代码依次顺序执行的。这是不是很颠覆你的认知?

计算机在执行程序的时候,并不会严格按照代码来顺序执行。比如第一个指令,是从内存中读取一个数据,而第二个指令,是寄存器的某个值自增1。而如果这两个指令是毫无冲突的,没有任何关联性和依赖性,谁先谁后都不影响最终结果。那么 “机智” 的CPU就有可能调换执行的顺序。比如第一个指令先通过总线去寻址、取数据,这需要很长的时间,CPU没必要非要等到这个数据从内存中取到并赋值了之后,才执行第二个指令。CPU可以先请求总线去取数据,等数据的时候就执行第二个指令,将寄存器里面的某个值自增1。说不定自增完了数据还没取过来。然后假设第三条指令要对这个读取到的数据进行操作了,那么CPU就只能等了,等到数据读取到了,赋值了,再进行第三条指令。因为CPU是在是太快了,比内存的速度快两个数量级!

所以,我们知道了计算机在执行代码的时候,是会为了提高效率,根据上下文来进行指令重排的。但是这个听起来很玄乎,能不能证明呢?接下来的一个例子,就能够通过Java语言来证明,Java代码并不是一定按照代码的顺序,一句一句依次顺序执行的:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author: LiYang
 * @Date: 2020/6/13 11:19
 * @Description: 证明Java代码执行中存在指令重排
 */
public class Disorder {

    //四个独立的类静态变量
    private static int a = 0;
    private static int b = 0;
    private static int x = 0;
    private static int y = 0;

    /**
     * 证明Java代码执行中存在指令重排的情况
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {

        //计数
        int count = 0;

        //线程池,固定两个线程
        ExecutorService executor = Executors.newFixedThreadPool(2);

        //一直执行,直到出现指令重排
        while (true) {

            //所有变量全部恢复初始值
            a = 0;
            b = 0;
            x = 0;
            y = 0;

            //计数加1
            count ++;

            //倒计时门栓,同步两个线程
            CountDownLatch latch = new CountDownLatch(2);

            //第一个线程
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    a = 1;
                    y = b;
                    latch.countDown();
                }
            });

            //第二个线程
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    b = 1;
                    x = a;
                    latch.countDown();
                }
            });

            //阻塞以上两个线程,等两个线程全部执行完毕后,继续执行下面的代码
            latch.await();

            //此时,上面的两个线程已经执行完毕。如果Java代码在执行过程中都是
            //一行一行的代码顺序执行的,那么上面两个线程无论是怎样的先后执行
            //顺序,a=1和b=1,这两句代码作为第一行代码,总有一句是最先执行的,
            //也就是说,到最后x或y肯定都不为0。如果到最后x和y都同时为0了,那
            //么根据反证法原理,Java代码在执行过程中,有可能并不绝对按照代码
            //顺序依次执行,当然也就发生了指令重排,Java代码执行中存在指令重排
            //的情况也就得到了证明

            //如果x和y都等于0了,就输出结果(如果Java代码真的按照顺序一句一句
            //执行的话,是绝对不可能出现x和y同时为0的)
            if (x == 0 && y == 0) {

                //指令重排输出语句
                String message = "第" + count + "次出现指令重排,x=" + x + ",y=" + y;

                //打印,证明完毕
                System.err.println(message);

                //结束程序
                System.exit(0);
            }
        }
    }

}

执行上面的代码,真的出现了x和y都为0的情况,通过反证法,也就证明了CPU在执行程序的过程中确实存在指令重排的现象,以Java为例,Java代码在执行过程中,并不一定是从上到下,每句代码依次顺序执行的(可能你的输出结果和我不一样,每次出现指令重排需要的时间不一定,有可能很快,也有可能要等很久):

95587次出现指令重排,x=0,y=0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章