1. 程式人生 > 實用技巧 >Java多執行緒之指令重排

Java多執行緒之指令重排

為什麼需要指令重排

通常一條指令的執行可以簡單分為以下幾個步驟:

  • 取指(都取指令) IF
  • 譯碼和去暫存器運算元 ID
  • 執行或者有效地址計算 EX
  • 儲存器訪問 MEM
  • 寫回 WB
    同樣的,彙編指令也不是一步就能執行完的,CPU實際工作時,需要分為多個步驟依次執行。

由於每個步驟都可能使用不同的硬體完成,因此聰明的工程師們發明了流水線技術來執行指令,如下圖所示:
在這裡插入圖片描述
CPU實際執行過程中,當執行到指令2時,指令1還沒開始執行,只是剛剛完成了取值操作而已,這樣的好處是加入每個指令都需要執行1ms,那麼指令2的執行不需要等待指令1 執行5ms後才能執行,只需要等待1ms就可以執行了,充分的利用了CPU的效能,但是流水線害怕中斷。

在這裡插入圖片描述
如上圖所示,當後續指令依賴前置指令結果時,流水線便會出現中斷。所以指令的重排序就是為了減少流水線的中斷,提高利用率。
指令重排後:
在這裡插入圖片描述

什麼情況不能指令重排

指令的重排序需要遵從Happen-Before規則:

  • 程式順序原則:一個執行緒內保證予以的序列性
  • volatile規則: volatile變數的寫,先於讀發生,保證了volatile變數的可見性
  • 鎖規則:解鎖必然發生在隨後的加鎖之前
  • 傳遞性:A先於B, B先於C,則A先於C
  • 執行緒的start()方法先於它的每一個動作
  • 執行緒的所有操作先於執行緒的終結(Thead.join())
  • 執行緒的中斷(interrupt())先於被中斷執行緒的程式碼
  • 物件的建構函式執行、結束先於finalize()方法

參考文獻 : 《Java 高併發程式設計》 葛一鳴 郭超