java編程語言容許線程訪問共享變量,爲了確保共享變量能被準確和一致的更新,線程應該確保經過排他鎖單獨得到這個變量。html
Java語言提供了volatile,在某些狀況下比鎖更加方便。若是一個字段被聲明成volatile,java線程內存模型確保全部線程看到這個變量的值是一致的。java
若想清楚理解volatile
關鍵字是如何保障共享變量在多線程之間正常使用的須要瞭解如下幾點編程
精簡一點,概念以下:緩存
指令在CPU中執行,CPU運行速度較快,所以爲減小從內存中頻繁讀寫數據的開銷,在cpu與內存的操做之間,有個高速緩存的的區域多線程
獲取數據流程:併發
上面的流程中,第一步會致使一致性問題,分析以下編程語言
若內存中Data已更新,但緩存中數據未更新,此時返回緩存中Data,返回的是舊數據測試
解決方案:ui
java內存模型,主要是爲了屏蔽不一樣的硬件,操做系統的內存訪問差別,使Java程序能夠達到跨平臺的目的,從而定義的一套模型操作系統
線程之間的共享變量存儲在主內存中,每一個線程都有一個私有的本地內存,本地內存保存該線程讀寫共享變量的副本
所以也存在上面的一致性問題,即如何保證線程對共享變量的修改後,其餘的線程能訪問到最新的共享變量
指令重排序
Java內存模型中,容許編譯器和處理器對指令進行重排序,可是重排序過程不會影響到單線程程序的執行,卻會影響到多線程併發執行的正確性
舉例說明
int i; boolean ans; i = 10; ans = true;
上面的代碼中,i
和ans
的賦值前後順序因爲指令重排,可能會出現ans=true
時,i
依然爲0的狀況
原子性
表示不可再繼續分割
可見性
一個線程對共享變量的修改,確保對其餘線程可見(即另外一個線程能訪問到修改後的數據)
volatile
進行聲明變量,保證可見順序行
程序執行的順序按照代碼的前後順序執行
volatile
禁止指令重排用法
volatile
便可做用
volatile
修飾的共享變量時,確保前面的代碼都執行完了)原理和實現機制
volatile
聲明的共享變量,會強制要求修改後的值寫入內存,並失效其餘線程的本地內存中的副本1.volatile
關鍵字沒法保證操做的原子性
2.volatile
關鍵字,禁止共享變量的指令重排,確保修改對全部線程當即可見
3.使用場景
int ans = i + j;
(也沒法保障準確性)經典的單例case寫法
class Singleton{ private volatile static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if(instance==null) { synchronized (Singleton.class) { if(instance==null) instance = new Singleton(); } } return instance; } }