將共享變量聲明為 volatile 後,對該變量的單次讀/寫操作具備以下特性:
long/double),但復合操作(如 volatile++)不具備原子性。這等價於使用同一把鎖同步該變量的單次讀/寫,但鎖能保證臨界區整體原子性,volatile 僅限單次操作。
從 JSR-133 起,volatile 寫-讀可實現線程間通信,其內存語義與鎖釋放-獲取一致:
示例:線程 A 執行 writer()(寫 a=1 再寫 flag=true),線程 B 執行 reader()(讀 flag 再讀 a)。因 flag 為 volatile,A 寫 flag 前的所有共享變量修改,在 B 讀 flag 後對 B 可見。
| 能否重排序 | 第二個操作 | 第一個操作 |
|---|---|---|
| 普通讀/寫 | volatile 讀 | volatile 寫 |
| 普通讀/寫 | NO | NO |
| volatile 讀 | NO | NO |
| volatile 寫 | NO | NO |
規則確保:volatile 寫之前的操作不會被重排到寫之後;volatile 讀之後的操作不會被重排到讀之前。
StoreStore 屏障。StoreLoad 屏障(全能屏障,開銷最大)。LoadLoad 和 LoadStore 屏障。在 x86 處理器上,除 StoreLoad 外其它屏障均可省略,故 volatile 寫開銷遠大於讀。
舊模型允許 volatile 與普通變量重排序,導致 volatile 寫-讀不具備鎖的內存語義。JSR-133 通過禁止此類重排序,使 volatile 成為比鎖更輕量的線程通信機制。