volatile是Java中用來作同步的一個關鍵字,以前對它的做用一直理解得不是很透徹。html
因而在網上查閱了一些資料,發現也講得含混不清。java
後來在wikipedia(http://en.wikipedia.org/wiki/Volatile_variable#In_Java)上看到了比較完善的解釋。總的來講,volatile關鍵字是用來防止編譯器作特定優化的,但具體做用取決於使用的語言(如C, C++, C#, Java)。多線程
在Java中,volatile的做用有兩點:函數
對volatile變量的修改可以馬上被其餘線程知道,也就是說,在讀取volatile變量的值時,不是從線程本地的cache讀取,而是從主內存讀取。這樣就能保證多線程對同一個變量的讀和寫有一個全局的順序。測試
能夠防止編譯器作額外的優化(如調整對變量的讀寫語句的執行順序,對while循環的優化等)。優化
網上的資料常常會給出相似這樣一個例子:spa
public class Thread1 extends Thread { private static boolean flag = false; public void run(){ while(!flag) { // ... } } public void close(){ flag = true; } }
網上的說法是:線程A在執行run()方法中的while循環,這時線程B調用了close()方法,結果線程A停不下來。由於編譯器觀察到while循環中沒有改變flag的值,就將while(!flag)優化成了while(true)。線程
開始我對編譯器是否會優化到這種程度表示懷疑。由於據我實際測試,不管對flag是否加volatile關鍵字修飾,都是能夠停下來的。據個人推測(根據上述volatile的做用第一點),線程A雖然不能在第一時間知道flag值的改變,可是最終仍是會讀到正確的值,從而中止while循環。code
後來我去掉volatile關鍵字,再將while循環的執行次數變長(例如達到1000000000次),這時再調用close()方法,線程A不會停下來了。因此可能HotSpot在while循環執行的次數足夠多時纔會作while(true)的優化。htm
對於volatile的第二點做用,還有這樣一個例子能夠用來解釋(來自http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile):
public class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42;
v = true;
}
public void reader() {
if (v == true) {
//uses x - guaranteed to see 42.
}
}
}
在註釋處,咱們但願看到的是x的值等於42。可是若是不加volatile修飾變量v,那麼編譯器有可能會調整writer()函數中兩條語句的執行順序,致使在註釋處x的值不肯定(也多是0)。加上volatile後,即可以防止編譯器爲了優化隨意調整語句的執行順序。
與普通加鎖方式的區別是:加鎖機制既能夠確保可見性又能夠確保原子性,而volatile變量只能確保可見性。