證明: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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章