Java四種內存屏障詳解,LoadLoad、LoadStore、StoreLoad、StoreStore
由于沒在官網查到相關資料,以下結論來自互聯網第三方博客搜集整理后,準確性無法保證,僅供參考。
屏障作用:
-
可見性:當一條線程修改了一個變量的值,新值會立即被寫入主內存,同時其他線程讀取該變量時會從主內存中讀取最新值,而不是使用線程緩存中的值。
-
有序性:編譯器和處理器可能會對指令進行重排以提高性能,但這種重排可能會導致其他線程看到不一致的狀態。變量的讀寫操作前后會插入特定的內存屏障,這些屏障會禁止指令重排,從而保證了操作的順序性。
屏障類別:
- LoadLoad(讀讀屏障):先執行屏障前的 讀,后執行屏障后的 讀。
- LoadStore(讀寫屏障):先執行屏障前的 讀,后執行屏障后的 寫。
- StoreLoad(寫讀屏障):先執行屏障前的 寫,后執行屏障后的 讀。
- StoreStore(寫寫屏障):先執行屏障前的 寫,后執行屏障后的 寫。
插入時機表:
| 屏障需求 | 第二個操作 | |||
| 第一個操作 | 普通讀 | 普通寫 |
volatile讀 獲取鎖 |
volatile寫 釋放鎖 |
| 普通讀 | LoadStore | |||
| 普通寫 | StoreStore | |||
|
volatile讀 獲取鎖 |
LoadLoad | LoadStore | LoadLoad | LoadStore |
|
volatile寫 釋放鎖 |
StoreLoad | StoreStore | ||
代碼示例:
class X {
int a, b;
volatile int v, u;
void f() {
int i, j;
i = a; // load a
j = b; // load b
/* 為什么這里volatile讀之前不插入屏障?如何保證可見性?
* 因為其他線程的volatile寫后的屏障必然會讓新值同步過來
* 所以這里無需屏障
*/
i = v; // load v
// LoadLoad - volatile讀 和 volatile讀 之間插入LoadLoad
j = u; // load u
// LoadStore - volatile讀 和 普通寫 之間插入LoadStore
a = i; // store a
b = j; // store b
// StoreStore - 普通寫 和 volatile寫 之間插入StoreStore
v = i; // store v
// StoreStore - volatile寫 和 volatile寫 之間插入StoreStore
u = j; // store u
// StoreLoad - volatile寫 和 volatile讀 之間插入StoreLoad
i = u; // load u
// LoadLoad - volatile讀 和 普通讀 之間插入LoadLoad
// LoadStore - volatile讀 和 普通寫 之間插入LoadStore
j = b; // load b
a = i; // store a
}
}
浙公網安備 33010602011771號