volatile 關鍵字
轉載自:https://javadoop.com/post/java-memory-model#toc10
volatile 的作用,記住兩點:記憶體可見性和禁止指令重排序。
volatile 的記憶體可見性
我們還是用 JMM 的主記憶體和本地記憶體抽象來描述,這樣比較準確。還有,並不是只有 Java 語言才有 volatile 關鍵字,所以後面的描述一定要建立在 Java 跨平臺以後抽象出了記憶體模型的這個大環境下。
還記得 synchronized 的語義嗎?進入 synchronized 時,使得本地快取失效,synchronized 塊中對共享變數的讀取必須從主記憶體讀取;退出 synchronized 時,會將進入 synchronized 塊之前和 synchronized 塊中的寫操作刷入到主存中。
volatile 有類似的語義,讀一個 volatile 變數之前,需要先使相應的本地快取失效,這樣就必須到主記憶體讀取最新值,寫一個 volatile 屬性會立即刷入到主記憶體。所以,volatile 讀和 monitorenter 有相同的語義,volatile 寫和 monitorexit 有相同的語義。
volatile 的禁止重排序
大家看下面的雙重檢查的單例模式,加個 volatile 能解決問題。其實就是利用了 volatile 的禁止重排序功能。
public static Singleton getInstance() {
if (instance == null) { //
Singleton temp;
synchronized (Singleton.class) { //
temp = instance;
if (temp == null) { //
synchronized (Singleton.class) { // 內嵌一個 synchronized 塊
temp = new Singleton();
}
instance = temp; //
}
}
}
return instance;
}
synchronized 在退出的時候,能保證 synchronized 塊中對於共享變數的寫入一定會刷入到主記憶體中。也就是說,上述程式碼中,內嵌的 synchronized 結束的時候,temp 一定是完整構造出來的,然後再賦給 instance 的值一定是好的。
可是,synchronized 保證了釋放監視器鎖之前的程式碼一定會在釋放鎖之前被執行(如 temp 的初始化一定會在釋放鎖之前執行完 ),但是沒有任何規則規定了,釋放鎖之後的程式碼不可以在釋放鎖之前先執行。
也就是說,程式碼中釋放鎖之後的行為 instance = temp
完全可以被提前到前面的 synchronized 程式碼塊中執行,那麼重排序問題就又出現了。
volatile 的禁止重排序並不侷限於兩個 volatile 的屬性操作不能重排序,而且是 volatile 屬性操作和它周圍的普通屬性的操作也不能重排序。
之前 instance = new Singleton() 中,如果 instance 是 volatile 的,那麼對於 instance 的賦值操作(賦一個引用給 instance 變數)就不會和建構函式中的屬性賦值發生重排序,能保證構造方法結束後,才將此物件引用賦值給 instance。
根據 volatile 的記憶體可見性和禁止重排序,那麼我們不難得出一個推論:執行緒 a 如果寫入一個 volatile 變數,此時執行緒 b 再讀取這個變數,那麼此時對於執行緒 a 可見的所有屬性對於執行緒 b 都是可見的。
volatile 小結
1.volatile 修飾符適用於以下場景:某個屬性被多個執行緒共享,其中有一個執行緒修改了此屬性,其他執行緒可以立即得到修改後的值。在併發包的原始碼中,它使用得非常多。
2.volatile 屬性的讀寫操作都是無鎖的,它不能替代 synchronized,因為它沒有提供原子性和互斥性。因為無鎖,不需要花費時間在獲取鎖和釋放鎖上,所以說它是低成本的。
3.volatile 只能作用於屬性,我們用 volatile 修飾屬性,這樣 compilers 就不會對這個屬性做指令重排序。
4.volatile 提供了可見性,任何一個執行緒對其的修改將立馬對其他執行緒可見。volatile 屬性不會被執行緒快取,始終從主存中讀取。
5.volatile 提供了 happens-before 保證,對 volatile 變數 v 的寫入 happens-before 所有其他執行緒後續對 v 的讀操作。
6.volatile 可以使得 long 和 double 的賦值是原子的。
相關文章
- Volatile關鍵字
- volatile關鍵字解析
- Volatile關鍵字剖析
- volatile關鍵字淺析
- 深入解析volatile關鍵字
- 快速理解 volatile 關鍵字
- Java volatile關鍵字作用Java
- Java volatile關鍵字解析Java
- Java關鍵字volatile的理解Java
- volatile 關鍵字的工作機制
- java併發之volatile關鍵字Java
- 兩張圖理解volatile關鍵字
- Java併發—— 關鍵字volatile解析Java
- C語言中volatile關鍵字的作用C語言
- Volatile關鍵字與執行緒安全執行緒
- Java記憶體模型——volatile關鍵字Java記憶體模型
- 每日一問:談談 volatile 關鍵字
- 深入瞭解 Java 的 volatile 關鍵字Java
- Volatile關鍵字&&DCL單例模式,volatile 和 synchronized 的區別單例模式synchronized
- volatile關鍵字在併發中有哪些作用?
- Java併發程式設計volatile關鍵字Java程式設計
- java多執行緒4:volatile關鍵字Java執行緒
- 為什麼我們需要volatile關鍵字?
- 深入彙編指令理解Java關鍵字volatileJava
- 深入理解Java中的volatile關鍵字Java
- java記憶體模型及volatile關鍵字Java記憶體模型
- java併發程式設計:volatile關鍵字Java程式設計
- Java多執行緒(二)volatile關鍵字Java執行緒
- java併發程式設計——volatile關鍵字Java程式設計
- Java併發程式設計:volatile關鍵字解析Java程式設計
- Java面試題集錦(1):volatile關鍵字Java面試題
- Java面試官最愛問的volatile關鍵字Java面試
- Java之併發程式設計:volatile關鍵字解析Java程式設計
- 多執行緒知識梳理(8) – volatile 關鍵字執行緒
- 執行緒安全(上)–徹底搞懂volatile關鍵字執行緒
- 執行緒安全(上)--徹底搞懂volatile關鍵字執行緒
- Java多執行緒學習(三)volatile關鍵字Java執行緒
- Java併發程式設計序列之執行緒間通訊-synchronized關鍵字-volatile關鍵字Java程式設計執行緒synchronized