1. 程式人生 > >Java併發(三):重排序

Java併發(三):重排序

在執行程式時為了提高效能,提高並行度,編譯器和處理器常常會對指令做重排序。重排序分三種類型:

  1. 編譯器優化的重排序。編譯器在不改變單執行緒程式語義的前提下,可以重新安排語句的執行順序。
  2. 指令級並行的重排序。現代處理器採用了指令級並行技術(Instruction-Level Parallelism, ILP)來將多條指令重疊執行。如果不存在資料依賴性,處理器可以改變語句對應機器指令的執行順序。
  3. 記憶體系統的重排序。由於處理器使用快取和讀/寫緩衝區,這使得載入和儲存操作看上去可能是在亂序執行。

問題:重排序都可能會導致多執行緒程式出現記憶體可見性問題

1)編譯器優化的重排序。編譯器在不改變單執行緒程式語義的前提下,可以重新安排語句的執行順序。

2)指令級並行的重排序。處理器多條指令重疊執行,改變語句對應機器指令的執行順序(處理器重排)

3)記憶體系統的重排序。處理器使用快取和讀/寫緩衝區,這使得載入和儲存操作看上去可能是在亂序執行(處理器重排)

舉例:處理器對記憶體的讀/寫操作的執行順序,不一定與記憶體實際發生的讀/寫操作順序一致,導致重排序導致記憶體可見性問題

  (處理器使用寫緩衝區來臨時儲存向記憶體寫入的資料:避免由於處理器停頓下來等待向記憶體寫入資料而產生的延遲

  以批處理的方式重新整理寫緩衝區,以及合併寫緩衝區中對同一記憶體地址的多次寫,可以減少對記憶體匯流排的佔用)

假設處理器A和處理器B按程式的順序並行執行記憶體訪問,最終卻可能得到x = y = 0的結果

第一步執行A1 B1

第二步執行A2 B2,此時已得到x=b=0 y=a=0

第三步執行A3 B3

執行完A3,A1才算執行完,A1 A2重排序了

JMM通過禁止特定型別的編譯器重排序和處理器重排序,為程式設計師提供一致的記憶體可見性保證

JMM的編譯器重排序規則會禁止特定型別的編譯器重排序

java編譯器在生成指令序列時,插入特定型別的記憶體屏障指令來禁止特定型別的處理器重排序