平時在閱讀jdk原始碼的時候,經常看到原始碼中有寫變數被volatile關鍵字修飾,但是卻不是十分清除這個關鍵字到底有什麼用處,現在終於弄清楚了,那麼我就來講講這個volatile到底有什麼用吧。
當乙個變數被定義為volatile之後,就可以保證此變數對所有執行緒的可見性,即當乙個執行緒修改了此變數的值的時候,變數新的值對於其他執行緒來說是可以立即得知的。可以理解成:對volatile變數所有的寫操作都能立刻被其他執行緒得知。但是這並不代表基於volatile變數的運算在併發下是安全的,因為volatile只能保證記憶體可見性,卻沒***對變數操作的原子性。比如下面的**:
/**
* 發起20個執行緒,每個執行緒對race變數進行10000次自增操作,如果**能夠正確併發,
* 則最終race的結果應為200000,但實際的執行結果卻小於200000。
* * @author colin wang
* */
public class volatiletest
private static final int threads_count = 20;
public static void main(string args)
}});
threads[i].start();
} while (thread.activecount() > 1)
thread.yield();
system.out.println(race);
}}
這便是因為race++操作不是乙個原子操作,導致一些執行緒對變數race的修改丟失。若要使用volatale變數,一般要符合以下兩種場景:
變數的運算結果並不依賴於變數的當前值,或能夠保證只有單一的執行緒修改變數的值。
變數不需要與其他的狀態變數共同參與不變約束。
使用volatile變數還可以禁止jit編譯器進行指令重排序優化,這裡使用單例模式來舉個例子:
/**
* 單例模式例程一
* * @author colin wang
* */
public class singleton_1
public static singleton_1 getinstacne()
}} return instance;
}}
/**
* 單例模式例程二
* * @author colin wang
* */
public class singleton_2
public static singleton_2 getinstacne()
}} return instance;
}}
變數在有了volatile修飾之後,對變數的修改會有乙個記憶體屏障的保護,使得後面的指令不能被重排序到記憶體屏障之前的位置。volalite變數的讀效能與普通變數類似,但是寫效能要低一些,因為它需要插入記憶體屏障指令來保證處理器不會發生亂序執行。即便如此,大多數場景下volatile的總開銷仍然要比鎖低,所以volatile的語義能滿足需求時候,選擇volatile要優於使用鎖。
深入分析Java中CAS機制
在jdk 1.5中增加的乙個最主要的支援是atomic類,比如說atomicinteger,atomiclong,這些類可幫助最大限度地減少在多執行緒中對於一些基本操作 例如,增加或減少多個執行緒之間共享的值 的複雜性。而這些類的實現都依賴於cas compare and swap 的演算法。但是,...
Java中的堆 棧 方法區深入分析
基本概念堆區 1.儲存的全部是物件,每個物件都包含乙個與之對應的 class 的資訊。class 的目的是得到操作指令 2.jvm 只有乙個堆區 heap 被所有執行緒共享,堆中不存放基本型別和物件引用,只存放物件本身。棧區 1.每個執行緒包含乙個棧區,棧中只儲存基礎資料型別的物件和自定義物件的引用...
new的深入分析
new 是c 的乙個關鍵字,同時也是操作符。關於new的話題非常多,因為它確實比較複雜,也非常神秘,下面我將把我了解到的與new有關的內容做乙個總結。new的過程 當我們使用關鍵字new在堆上動態建立乙個物件時,它實際上做了三件事 獲得一塊記憶體空間 呼叫建構函式 返回正確的指標。當然,如果我們建立...