聊聊 JAVA 中的 Volatile

Volatile是一種輕量級的同步機制,它有兩個主要特性:安全

  1. 保證共享變量對全部線程的可見性。
  2. 禁止指令重排序優化。

一. 保證共享變量對全部線程的可見性多線程

public class TestVolatile {	
	volatile boolean status = false;// 關鍵代碼 

	/**
	 * 狀態切換爲true
	 */
	public void changeStatus(){
		status = true;
	}

	/**
	 * 若狀態爲true,則running。
	 */
	public void run(){
		if(status){
			System.out.println("running....");
		}
	}
}

解析函數

  • 1.關鍵代碼處不加volatile的效果

不加,若是在多線程機制下, 在JVM 中 status是一個線程,run方法是另一個線程,兩個線程之間互不通信,所以無法保證執行完changestatus後,run函數會運行。優化

  • 2.關鍵代碼處加了volatile的效果

加了,則把status變量提高成內存共享變量,線程之間能夠互訪,所以在多線程環境下,也能保證run方法確定會執行。線程


P.S Volatile並不能徹底替代Synchronized,它依然是個輕量級鎖,在不少場景下,Volatile並不能勝任,譬如在複合類的操做下,沒法確保線程安全。 例如:num++,這是一個複合型操做,拆解步驟就是:code

  1. 取值
  2. 加法運算
  3. 賦值

Volatile 只能保證原子性操做的線程安全,對於複合型操做則沒法起到預期的目的,關於這點的改進,能夠參考Volatile的第二特徵,也能夠借鑑 JAVA AtomicInteger 源代碼,利用的也是Volatile的第二特徵。排序


二.禁止指令重排序優化內存

Volatile指令的排序規則:編譯器

  1. 當第二個操做是voaltile寫時,不管第一個操做是什麼,都不能進行重排序。
  2. 當地一個操做是volatile讀時,無論第二個操做是什麼,都不能進行重排序。
  3. 當第一個操做是volatile寫時,第二個操做是volatile讀時,不能進行重排序。

`同步

int a = 1;  // 1
int b = 2; //2
int c = a + b; // 3

`

解析

  • a,b 直接賦值,不存在數據依賴,所以 // 1,2 編譯器或解析器對這兩處的代碼能夠存在重排序優化。
  • c 存在數據依賴,依賴a,b;所以不存在數據依賴。
  • 若是要保證a,b 按順序執行,加上 Volatile 便可,限制編譯器或解析器對其進行排序優化。
相關文章
相關標籤/搜索