Java多執行緒——volatile
volatile關鍵字介紹
volatile修飾的變數在多處理器開發中保證了共享變數的“可見性”。可見性的意思是當一個執行緒修改一個共享變數時,另外一個執行緒能讀到這個修改的值。Java中的volatile關鍵字用作Java編譯器和Thread的指示符,它們不會快取此變數的值並始終從主存中讀取它。
Java在Java記憶體模型(JMM)中引入了一些變化,它保證了從一個執行緒到另一個執行緒的變化的可見性,也就是“happens-before”在一個執行緒中發生的記憶體寫入的問題可能“洩漏”並被另一個執行緒看到。

圖片來自: http://javarevisited.blogspot.jp/2011/06/volatile-keyword-java-example-tutorial.html
volatile使用要點
Java中的volatile關鍵字保證volatile變數的值總是從主儲存器讀取而不是從執行緒的本地快取讀取。
在Java中,對於使用Java volatile關鍵字(包括long和double變數)宣告的所有變數,讀寫操作都是原子性的。
在變數中使用Java中的volatile關鍵字可以減少記憶體一致性錯誤的風險,因為對Java中volatile變數的任何寫入與該變數的後續讀取建立了一個happens-before關係。
對於大多數基本變數(除long和double之外的所有型別),即使沒有在Java中使用volatile關鍵字,對於引用變數的讀和寫是原子的。
對Java中volatile變數的訪問從來沒有機會阻塞,因為我們只做一個簡單的讀或寫,因此與synchronized塊不同,我們永遠不會持有任何鎖或等待任何鎖。
作為物件引用的Java volatile變數可以為null。
Java volatile關鍵字並不意味著原子,比如對宣告volatile變數 i++ 操作並不是原子的,使操作原子你仍然需要確保使用synchronized方法或在Java中的塊進行獨佔訪問。
如果變數不在多個執行緒之間共享,則不需要對該變數使用volatile關鍵字。
與synchronized的區別
Java中的volatile關鍵字是一個欄位修飾符,而同步修改程式碼塊和方法。
synchronized需要獲取和釋放監視器鎖,而 volatile關鍵字不需要持有鎖。
在Java中的執行緒可以被阻塞以等待任何監視器在同步的情況下,而Java中的volatile關鍵字不是這樣。
同步方法比Java中的volatile關鍵字影響效能。
由於Java中的volatile關鍵字僅同步執行緒記憶體和“主”記憶體之間的一個變數的值,而同步則同步執行緒記憶體和“主”記憶體之間的所有變數的值,並鎖定和釋放監視器以進行引導。由於這個原因,Java中的synchronized關鍵字很可能比volatile具有更多的開銷。
不能在空物件上同步,但Java中的volatile變數可以為null。
示例程式碼
這裡舉例說明volatile修飾變數的複合操作 i++ 不具有原子性。
public class VolatilePractice {
private volatile int i = 0;
public int get(){
return i; ////單個volatile變數的讀與寫具有原子性
}
public void set(int n){
this.i = n;
}
//如果在方法上加synchronized修飾
public void getAndIncrement(){
i++; //複合(多個)volatile變數的讀/寫不具有原子性
}
public static void main(String[] args){
VolatilePractice volatilePractice = new VolatilePractice();
ExecutorService executorService = Executors.newFixedThreadPool(30);
for(int i = 0; i < 10000; i++){
executorService.execute(new VolatileAtomicity(volatilePractice));
}
executorService.shutdown();
//判斷是否所有執行緒執行完成
while(executorService.isTerminated()){
System.out.println(volatilePractice.get());
break;
}
}
}
class VolatileAtomicity implements Runnable{
private VolatilePractice volatilePractice;
public VolatileAtomicity(VolatilePractice volatilePractice){
this.volatilePractice = volatilePractice;
}
public void run(){
volatilePractice.getAndIncrement();
}
}
如果 i++ 操作是原子的,正常情況下列印的結果應該是10000,但實際每次的結果大都不同並且小於10000; 如果在 getAndIncrement() 方法上加 synchronized 關鍵字(或者方法內用 lock 等),就能保證該方法操作的原子性了,就會得到輸出值 10000 了。
參考資料
How Volatile in Java works? Example of volatile keyword in Java
Java併發程式設計:volatile關鍵字解析
相關文章
- Java多執行緒(四):volatileJava執行緒
- Java多執行緒(六) volatileJava執行緒
- java多執行緒之volatile理解Java執行緒
- Java多執行緒之初識volatileJava執行緒
- Java多執行緒(二)volatile關鍵字Java執行緒
- java多執行緒4:volatile關鍵字Java執行緒
- Java多執行緒/併發09、淺談volatileJava執行緒
- Java多執行緒(一)之volatile深入分析Java執行緒
- Java多執行緒學習(三)volatile關鍵字Java執行緒
- Java多執行緒程式設計那些事:volatile解惑Java執行緒程式設計
- Java多執行緒——執行緒Java執行緒
- Java 執行緒和 volatile 解釋Java執行緒
- Java多執行緒開發|volatile與偽共享問題Java執行緒
- java多執行緒與併發 - volatile的作用及原理Java執行緒
- Java多執行緒-執行緒中止Java執行緒
- Java多執行緒——執行緒池Java執行緒
- 【Java多執行緒】輕鬆搞定Java多執行緒(二)Java執行緒
- java——多執行緒Java執行緒
- java 多執行緒Java執行緒
- 【Java】多執行緒Java執行緒
- JAVA 多執行緒 ??Java執行緒
- java多執行緒Java執行緒
- Java - 多執行緒Java執行緒
- Java多執行緒之三volatile與等待通知機制示例Java執行緒
- java 多執行緒守護執行緒Java執行緒
- Java多執行緒-執行緒通訊Java執行緒
- Java多執行緒-執行緒狀態Java執行緒
- Java多執行緒(2)執行緒鎖Java執行緒
- java多執行緒9:執行緒池Java執行緒
- Java多執行緒之執行緒中止Java執行緒
- 【java多執行緒】(二)執行緒停止Java執行緒
- Java多執行緒——守護執行緒Java執行緒
- Java多執行緒16:執行緒組Java執行緒
- Java多執行緒18:執行緒池Java執行緒
- 多執行緒基礎之synchronized和volatile執行緒synchronized
- Java多執行緒學習(一)Java多執行緒入門Java執行緒
- Java多執行緒(一)多執行緒入門篇Java執行緒
- Java多執行緒-執行緒池的使用Java執行緒