當前位置:才華齋>計算機>java語言>

解析Java中volatile關鍵字

java語言 閱讀(1.37W)
  解析Java中volatile關鍵字

在java多執行緒程式設計中經常volatile,有時候這個關鍵字和synchronized 或者lock經常有人混淆,具體解析如下:

解析Java中volatile關鍵字

在多執行緒的環境中會存在成員變數可見性問題: java的每個執行緒都存在一個執行緒棧的記憶體空間,該記憶體空間儲存了該執行緒執行時的變數資訊,當執行緒訪問某一個變數值的時候首先會根據這個變數的地址找到物件的堆記憶體或者是棧堆存(原生資料型別)中的具體的.內容,然後把這個內同賦值一個副本儲存在本執行緒的執行緒棧中,緊接著對這個變數的一切操作線上程完成退出之前都和堆疊記憶體中的變數內容是沒有關係的,操作的是自己執行緒棧中的副本。當操作完後會把操作完的結果寫回到主記憶體中。假如有兩個執行緒A和B,同事操作某一個變數x;A對x進行了加1操作,那麼B獲取的副本可能是x加1後的結果,也可能是x;為了保證獲取記憶體中最新的資料變數 需要加上 volatile 關鍵字,這樣在每次對x進行操作的時候都會去檢查下執行緒棧中的變數的值是不是和住記憶體中變數的值一樣,如果不一樣會重新load。

eg:

public class ThreadSee { //t1執行緒會根據flag的值做對應的操作,主執行緒會更改t1的值 public static void main(String[] args) throws InterruptedException { ThReadTest th= new ThReadTest(); Thread t1 = new Thread(th); t(); p(1000); geFlag(); p(2000); tln(lag()); } } class ThReadTest implements Runnable{ //執行緒訪問變數時會把其load到對應的執行緒棧中,每次操作時都要獲取記憶體中最新的資料 private volatile boolean stopflag; @Override public void run() { int i=0; while(!stopflag){ i++; tln("=="+entThread()ame()); } tln("Thread finish:"+i); } public void changeFlag(){ flag=true; tln(entThread()ame()+"***********"); } public boolean getFlag(){ return stopflag; } }

上述程式碼如果去掉volatile,會一直死迴圈執行下去。

但是volatile不能保證執行緒安全的同步

eg:

public class ThreadSave implements Runnable{ static ThreadSave sync = new ThreadSave(); static volatile int j=0; //Lock lock =new ReentrantLock(); public void inscane(){ // (); for(int i=0;i<10000000;i++){ j++; } // ck(); } @Override public void run() { inscane(); } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(sync); Thread t2 = new Thread(sync); t(); t(); (); (); tln(j); } }

根據上述程式碼執行的結果不是預期20000000,

因為對於volatile修飾的變數,jvm虛擬機器只是保證從主記憶體載入到執行緒工作記憶體的值是最新的。

例如假如執行緒1,執行緒2 在進行執行緒棧與主記憶體read,load 操作中,發現主記憶體中count的值都是5,那麼都會載入這個最新的值

線上程1堆count進行修改之後,會write到主記憶體中,主記憶體中的count變數就會變為6;

執行緒2由於已經進行read,load操作,在進行運算之後,也會更新主記憶體count的變數值為6;

導致兩個執行緒及時用volatile關鍵字修改之後,還是會存在併發的情況。

綜上所述:

volatile只會保證執行緒去做一個檢查當前執行緒棧的變數值和主記憶體中資料值是否一樣的這麼一個動作,只此而已。而lock或者是synchronized 會保證某一時刻只有單個執行緒進入該方法,從而確保其執行緒安全性。

所以在如果多個執行緒去修改一個volatile變數那麼沒有實際的邏輯意義。如果一個執行緒去修改其他的執行緒依賴修改的變數值,此時是有作用的。

以上就是本文的全部內容,希望對大家的學習有所幫助。