循序運行
主條目:指令周期
在早期的處理器中疏橄,指令的執(zhí)行一般在以下的步驟中完成:
1 指令獲取蝶怔。
2 如果輸入的運算對象是可以獲取的(比如已經(jīng)存在于寄存器中)奶浦,這條指令會被發(fā)送到合適的功能單元。如果一個或者更多的運算對象在當(dāng)前的時鐘周期中是不可獲取的(通常需要從主存獲忍咝恰)澳叉,處理器會開始等待直到它們是可以獲取的。
3 指令在合適的功能單元中被執(zhí)行沐悦。
4 功能單元將運算結(jié)果寫回寄存器成洗。
亂序執(zhí)行
這種范式通過以下步驟挑選可執(zhí)行的指令先運行:
1 指令獲取。
2 指令被發(fā)送到一個指令序列中(也稱執(zhí)行緩沖區(qū)或者保留站)藏否。
3 指令將在序列中等待直到它的數(shù)據(jù)運算對象是可以獲取的瓶殃。然后指令被允許在先進入的、舊的指令之前離開序列緩沖區(qū)副签。
4 指令被分配給一個合適的功能單元并由之執(zhí)行遥椿。
5 結(jié)果被放到一個序列中。
6 僅當(dāng)所有在該指令之前的指令都將他們的結(jié)果寫入寄存器后继薛,這條指令的結(jié)果才會被寫入寄存器中修壕。這個過程被稱為畢業(yè)或者退休周期。
亂序執(zhí)行的重要概念是實現(xiàn)了避免計算機在用于運算的對象不可獲取時的大量等待遏考。在上述文字的要點中慈鸠,亂序執(zhí)行處理器避免了在順序執(zhí)行處理器處理過程第二步中當(dāng)指令由于運算數(shù)據(jù)未到位所造成的等待。
例如:
b = a * 5
v = b++
c = a + 3
由于1與3可并發(fā)運行,而2之b無法隨即獲得青团,因此可以先計算乘法1與加法3譬巫,再運行2。
證明CPU亂序執(zhí)行存在
public class OutOfOrder {
private static int x = 0, y = 0;
private static int a = 0, b = 0;
public static void main(String[] args) throws InterruptedException {
int i = 0; // 記錄次數(shù)
for (;;) {
i++;
x = 0; y = 0;
a = 0; b = 0;
Thread one = new Thread(new Runnable() {
@Override
public void run() {
a = 1;
x = b;
}
});
Thread two = new Thread(new Runnable() {
@Override
public void run() {
b = 1;
y = a;
}
});
one.start();two.start();
one.join();two.join();
if (x == 0 && y ==0) {
System.out.println("第"+i+"次督笆,出現(xiàn)("+x+","+y+")");
break;
}
}
}
}
正常執(zhí)行期待的結(jié)果不會出現(xiàn)x和y同時為0的情況
demo中測試的是語句級亂序的現(xiàn)象芦昔,語句級亂序的發(fā)生說明必定存在指令級亂序
如果出現(xiàn)則說明CPU存在亂序執(zhí)行
結(jié)果: