在多核處理器的環境下:編譯器可能改變兩個操做的前後順序;處理器可能不是徹底依照程序的目標代碼所指定的順序執行命令;一個處理器執行的多個操做,在其餘處理器的角度來看,其順序可能與目標代碼所指定的順序不一致。這種現象就叫重排序。java
重排序類型 | 含義 |
---|---|
LoadLoad重排序 | 該重排序指一個處理器上前後執行兩個讀內存操做L1和L2,其餘處理器對這兩個內存操做的感知順序多是L2——>L1,即L1被重排序到L2以後。 |
StoreStore重排序 | 該重排序指一個處理器上前後執行兩個寫內存操做W1和W2,其餘處理器對這兩個內存操做的感知順序多是W2——>W1,即W1被重排序到W2以後。 |
LoadStore重排序 | 該重排序指一個處理器上前後執行讀內存操做L1和寫內存操做W2,其餘處理器對這兩個內存操做的感知順序多是W2——>L1,即L1被重排序到W2以後。 |
StoreLoad重排序 | 該重排序指一個處理器上前後執行寫內存操做W1和讀內存操做L2,其餘處理器對這兩個內存操做的感知順序多是L2——>W1,即W1被重排序到L2以後。 |
內存重排序與具體的處理器微架構有關,基於不一樣微架構的處理器所容許的內存重排序是不一樣的,這裏再也不闡述。編程
對於編譯器,JMM的編譯器重排序規則會禁止特定類型的編譯器重排序緩存
對於處理器重排序,JMM的處理器重排序規則會要求Java編譯器在生成指令序列時,插入特定類型的內存屏障指令,經過內存屏障指令來禁止特定類型的處理器重排序。安全
數據依賴性: 若是兩個操做訪問同一個變量,且這兩個操做中有一個爲寫操做,此時這兩個操做之間就存在數據依賴性。數據依賴分爲下列3種類型: 1.寫後讀:a=1;b=a; 2.寫後寫:a=1;a=2; 3.讀後寫:a=b;b=1;
爲了遵照as-if-serial語義,編譯器和處理器在重排序時,會遵照數據依賴性,編譯器和處理器不會改變存在數據依賴關係的兩個操做的執行順序。由於這種重排序會改變執行結果。
不一樣處理器之間和不一樣線程之間的數據依賴性不被編譯器和處理器考慮。多線程
在單線程程序中,對存在控制依賴的操做重排序,不會改變執行結果(這也是as-if-serial語義容許對存在控制依賴的操做作重排序的緣由);但在多線程程序中,對存在控制依賴的操做重排序,可能會改變程序的執行結果。架構
當操做1和操做2重排序時
當操做3和操做4重排序時
重排序在這裏破壞了多線程程序的語義!併發
經過加鎖同步可解決該問題
性能
參考資料:
1.Java併發編程的藝術(方騰飛 魏鵬 程曉明 著)
2.Java多線程編程實戰指南(黃文海 著)優化