說下機器環(huán)境
- 機器是win10系統(tǒng),4核處理器
- java版本是:
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
寫個用例測試
在一個main方法里啟動兩個線程循環(huán),然后計算時間
public static void main(String[] args) throws InterruptedException {
int count = 500000000; // 數(shù)組大小
int arr[] = new int[count];
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
for (int i = 0; i < arr.length; i++) {
}
System.out.println("直接計算長度-time1 = " + (System.currentTimeMillis() - start));
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
for (int i = 0, len = arr.length; i < len; i++) {
}
System.out.println("一次計算長度-time2 = " + (System.currentTimeMillis() - start));
}
});
t1.start();
t2.start();
t1.join();
t2.join();
}
多次計算后可以看到的結(jié)果是:一次計算數(shù)組長度的時間均優(yōu)于直接計算數(shù)組長度的時間
即:time2<=time1
一次計算長度-time2 = 2
直接計算長度-time1 = 3
- 由此簡單得出透揣,通過中間變量一次性計算循環(huán)長度優(yōu)于每次循環(huán)都去計算數(shù)組長度
在for循環(huán)中,為什么每次都要去計算數(shù)組長度川抡,編譯器不會優(yōu)化嗎?
因為時間差別并不是很大须尚,每次也就0~3毫秒的影響崖堤,是不是機器差別影響的呢?
前面列舉出機器cpu數(shù)量耐床,只啟動了兩個線程去運行密幔,幾乎是并行的,可以排除機器差別撩轰。
- 還不放心胯甩,我們反編譯看一下編譯過程
javap字節(jié)碼分析
為了編譯過期盡量清晰昧廷,我們最簡化程序
- 1.程序1-for中直接計算數(shù)組長度
package com.maxbin.swap;
public class For1 {
public static void main(String[] args) {
int arr[] = new int[1000000];
for (int i = 0; i < arr.length; i++) {
}
}
}
- 2.程序2-for中使用中間變量一次計算數(shù)組長度
package com.maxbin.swap;
public class For2 {
public static void main(String[] args) {
int arr[] = new int[1000000];
for (int i = 0, len = arr.length; i < len; i++) {
}
}
}
- javac 編譯源碼
javac -encoding utf-8 For1.java
javac -encoding utf-8 For2.java
目錄下會生成對應(yīng)的clss字節(jié)碼文件
javap 查看字節(jié)碼
程序1-for中直接計算數(shù)組長度的字節(jié)碼
F:\tmp\clazz>javap -c For1.class
Compiled from "For1.java"
public class com.maxbin.swap.For1 {
public com.maxbin.swap.For1();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // int 1000000
2: newarray int
4: astore_1
5: iconst_0
6: istore_2
7: iload_2
8: aload_1
9: arraylength
10: if_icmpge 19
13: iinc 2, 1
16: goto 7
19: return
}
- 程序2-for中使用中間變量一次計算數(shù)組長度的字節(jié)碼
F:\tmp\clazz>javap -c For2.class
Compiled from "For2.java"
public class com.maxbin.swap.For2 {
public com.maxbin.swap.For2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // int 1000000
2: newarray int
4: astore_1
5: iconst_0
6: istore_2
7: aload_1
8: arraylength
9: istore_3
10: iload_2
11: iload_3
12: if_icmpge 21
15: iinc 2, 1
18: goto 10
21: return
}
字節(jié)碼是使用匯編語言,雖然程序2的匯編源碼長度長于程序1偎箫,但是往下看:
程序1
10行:if_icmpge(如果一個int類型值大于或者等于另外一個int類型值木柬,則跳轉(zhuǎn))判斷條件,成立則跳轉(zhuǎn)19行return淹办;否則往下走眉枕,看13行;
13行:iinc(把一個常量值加到一個int類型的局部變量上邏輯運算)對應(yīng) i++ 操作怜森;
16行:goto跳轉(zhuǎn)到第7行速挑;
7行:從局部變量2中裝載int類型值;
8行:從局部變量1中裝載引用類型值
9行:獲取數(shù)組長度
由此副硅,可以看出每一次循環(huán)中都會去獲取一次數(shù)組長度程序2
程序2直接看18行的goto語句姥宝,跳轉(zhuǎn)到10;
在第8行即獲取了數(shù)組長度恐疲,然后在10-18行的循環(huán)中并未出現(xiàn)“arraylength”指令獲取數(shù)組長度
- 分析字節(jié)碼可以了解程序的具體執(zhí)行指令