Java中"或"運算與"與"運算快慢的三三兩兩

先上結論

模運算運算慢20%到30%

這是經過實驗的方式獲得的結論.由於沒有大大能夠進行明確指導,因此我以最終運行的結果爲準.歡迎指正.java

測試代碼

@Test
public void test10() {
    int a, b, temp, count = 100000000;
    long start, time;

    Random random = new Random();


    while (true) {
        System.out.println("-----------------------------------------------");
        a = random.nextInt();
        b = random.nextInt();

        // 模運算部分
        start = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            temp = a % b;
            preventOptimization(temp);
        }
        long modulo = System.currentTimeMillis() - start;

        // 與運算部分
        start = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            temp = a & b;
            preventOptimization(temp);
        }
        long and = System.currentTimeMillis() - start;

        // 計算兩種運算的比
        BigDecimal bigDecimal = new BigDecimal(and)
                .divide(new BigDecimal(modulo), 6, ROUND_DOWN);
        System.out.println(String.format("modulo: %sms, and: %sms, scale: %s", modulo, and, bigDecimal));
    }
}

//    private static int preventOptimizationVar = 0; // A

/**
 * 用於阻止jvm的字節碼優化技術生效,優化掉for循環中的代碼<br>
 *
 * @param num
 */
private static void preventOptimization(int num) {
//        preventOptimizationVar += num; // A
}

注意事項

啓動時,須要添加JVM參數-Djava.compiler=NONE阻止虛擬機的JIT優化ubuntu

一些迷之調用的解釋

  1. 方法preventOptimization的做用原本是爲了防止for循環內的運算單元被優化.從結果看,沒法抵禦JIT優化,實際上只阻止了字節碼優化.
  2. 一樣是方法preventOptimization.內部添加了一個對成員變量preventOptimizationVar的操做,本意一樣是是爲了阻止JIT優化,但效果出現誤差.
  3. 最終,只能使用JVM參數-Djava.compiler=NONE阻止JIT優化,同時調用空方法preventOptimization阻止字節碼優化
  4. 爲了整理其中的關聯,進行以下整理

針對preventOptimization方法,preventOptimizationVar操做與-Djava.compiler=NONE參數之間的交叉測試

--------------------------- -Djava.compiler=NONE 不使用-Djava.compiler=NONE
preventOptimization(空方法) 目標結果 只能執行第一次while,以後除數爲0拋出異常.應該是for循環被優化掉了
preventOptimization 執行變得極慢且比值隨機位於1兩側.多是由於操做成員變量的時間已經把運算的時間稀釋了 兩種運算的for的平均用時只有個位數的毫秒數.通常爲4ms或5ms.能夠判定發生了JIT優化.可是這又與徹底跳過for循環的行爲不一樣.中間產生了數毫秒的操做時間.
不調用preventOptimization 目標結果 只能執行第一次while,以後除數爲0拋出異常.應該是for循環被優化掉了

注: 上面的測試結果基於intel平臺上的ubuntu18.4操做系統.後面我會補上AMD平臺上的Windows系統的執行表格.它們之間會有輕微的不一樣dom

後記

  1. 針對-Djava.compiler=NONE,明確的禁用了JIT優化
  2. 針對字節碼優化須要回去翻書確認實際做用與效果
  3. 這個代碼在不一樣的物理機上出現了一些差別.家中的電腦是AMD的銳龍CPU,其結果恆定爲0.73左右.而在公司的Intel CPU上運行,結果穩定在0.87左右.
  4. 目前我沒法這種計算方式是不是正確的,雖然得出了模運算運算慢的結論.身邊沒有大大,沒法對個人這種作法進行評價.也就沒法肯定結果的正確性.也就是說,我有可能用了錯誤的方式,獲得這正確的答案.這種可能的本末倒置實在讓人頭痛.

後記的後記

對於目前的這種狀況.要想徹底弄清誰快誰慢,其實能夠用一個最簡單也最直觀的方法進行確認.那就是去翻JDK源碼.先在字節碼裏找到負責運算與運算的指令,而後去找這個指令JDK實現jvm

更新

看了下編譯後的字節碼,代碼中使用了以下的指令進行操做

  1. 運算使用指令irem.將操做數棧的兩個值進行餘運算(注意,這裏用的是餘運算.它不一樣於模運算)
  2. 運算使用指令iand.將操做數棧的兩個值進行與運算

下面須要找到JDK是怎麼執行字節碼文件中的每一個指令的.

不要和我說什麼幾個階段,每一個階段都幹什麼.這多是個大坑.因此我得翻書(鴿了)啊ide

相關文章
相關標籤/搜索