一、什麼是Volatile關鍵字
Volatile關鍵字用於表明變數可能會在任意時刻被修改,它告訴編譯器不要優化處理這個變數,而是每次都從內存中讀取它的值。Volatile關鍵字本質上是告訴編譯器,這個變數的值可能會發生變化,所以在讀取這個變數的時候必須從內存中重新獲取,而不是使用緩存中的副本。
二、Volatile關鍵字的使用場合
1、多線程訪問同一個變數。
public class VolatileExample { private volatile boolean flag = false; public void setFlag() { flag = true; } public void whileFlag() { while (!flag) { // do something } } }
在這個例子中,如果不加volatile關鍵字,一個線程設置flag值為true時,其他線程不一定能夠立即看到flag值的變化,從而有可能導致死循環。加上volatile關鍵字後,寫操作會立即刷新到主內存中,讀操作也會直接從主內存中獲取最新的值。
2、操作系統中的中斷(interrupt)。
private volatile boolean isRunning = true; public void run() { while (isRunning) { // do something } } public void stop() { isRunning = false; }
在這個例子中,如果不加volatile關鍵字,當stop方法把isRunning設置為false時,run方法中的while循環有可能無法及時退出。
三、Volatile關鍵字的實現原理
Java中的Volatile關鍵字通過禁止JVM對變數的操作進行重排序來保證線程的可見性。
根據volatile變數的定義,對該變數的修改會立即刷新到主內存中,而在線程讀取該變數時,會直接從主內存中獲取最新的值。但是,由於程序的運行和處理過程不可控,JVM含有重排序策略,會在執行代碼時對其進行優化。在需要提高CPU運行效率或減小內存訪問延遲的情況下,會把代碼中訪問內存的順序打亂,以便提高性能。但是,這種優化可能導致多線程訪問共享內存時出現異常,因為多線程訪問時共享內存在各個線程之間不可見。
為了解決這個問題,Java使用了內存屏障機制,來禁止對volatile變數操作語義重排。
private static volatile int i = 0; public static void main(String[] args) { while (i == 0) { // do something } }
例如,在上述例子中,如果不加volatile關鍵字,代碼可能會無限循環,而加上volatile關鍵字後,JVM會在while循環之前插入一個內存屏障,保證i的修改操作先於while循環的讀操作。
四、Volatile關鍵字的注意事項
1、Volatile不能保證原子性。當多個線程在同時修改一個volatile變數的值時,可能會出現數據不一致的情況。解決這個問題的辦法是使用synchronized或Atomic類。
2、Volatile關鍵字應該只用於一些單一的、輕量級的任務。如果需要數據同步或者加鎖等重量級的操作,應該使用synchronized或Lock。
3、Volatile變數的讀取和修改操作一般情況下耗時較長,建議在高並發情況下使用局部變數代替volatile變數。
五、使用Volatile關鍵字的代碼示例
public class VolatileExample { private volatile int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } }
在這個例子中,使用Volatile關鍵字保證多個線程操作count變數的可見性。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/192867.html