3.volatile能保證有序性嗎?
在前面提到volatile關鍵字能禁止指令重排序,所以volatile能在一定程度上保證有序性。
volatile關鍵字禁止指令重排序有兩層意思:
1)當程序執行到volatile變量的讀操作或者寫操作時,在其前面的操作的更改肯定全部已經進行,且結果已經對後面的操作可見;在其後面的操作肯定還沒有進行;
2)在進行指令優化時,不能將在對volatile變量訪問的語句放在其後面執行,也不能把volatile變量後面的語句放到其前面執行。
可能上面說的比較繞,舉個簡單的例子:
1 2 3 4 5 6 7 8 | //x、y爲非volatile變量 //flag爲volatile變量 x = 2 ; //語句1 y = 0 ; //語句2 flag = true ; //語句3 x = 4 ; //語句4 y = - 1 ; //語句5 |
由於flag變量爲volatile變量,那麼在進行指令重排序的過程的時候,不會將語句3放到語句1、語句2前面,也不會講語句3放到語句4、語句5後面。但是要注意語句1和語句2的順序、語句4和語句5的順序是不作任何保證的。
並且volatile關鍵字能保證,執行到語句3時,語句1和語句2必定是執行完畢了的,且語句1和語句2的執行結果對語句3、語句4、語句5是可見的。
那麼我們回到前面舉的一個例子:
1 2 3 4 5 6 7 8 9 | //線程1: context = loadContext(); //語句1 inited = true ; //語句2 //線程2: while (!inited ){ sleep() } doSomethingwithconfig(context); |
前面舉這個例子的時候,提到有可能語句2會在語句1之前執行,那麼久可能導致context還沒被初始化,而線程2中就使用未初始化的context去進行操作,導致程序出錯。
這裏如果用volatile關鍵字對inited變量進行修飾,就不會出現這種問題了,因爲當執行到語句2時,必定能保證context已經初始化完畢。
4.volatile的原理和實現機制
前面講述了源於volatile關鍵字的一些使用,下面我們來探討一下volatile到底如何保證可見性和禁止指令重排序的。
下面這段話摘自《深入理解Java虛擬機》:
“觀察加入volatile關鍵字和沒有加入volatile關鍵字時所生成的彙編代碼發現,加入volatile關鍵字時,會多出一個lock前綴指令”
lock前綴指令實際上相當於一個內存屏障(也成內存柵欄),內存屏障會提供3個功能:
1)它確保指令重排序時不會把其後面的指令排到內存屏障之前的位置,也不會把前面的指令排到內存屏障的後面;即在執行到內存屏障這句指令時,在它前面的操作已經全部完成;
2)它會強制將對緩存的修改操作立即寫入主存;
3)如果是寫操作,它會導致其他CPU中對應的緩存行無效。
五.使用volatile關鍵字的場景
synchronized關鍵字是防止多個線程同時執行一段代碼,那麼就會很影響程序執行效率,而volatile關鍵字在某些情況下性能要優於synchronized,但是要注意volatile關鍵字是無法替代synchronized關鍵字的,因爲volatile關鍵字無法保證操作的原子性。通常來說,使用volatile必須具備以下2個條件:
1)對變量的寫操作不依賴於當前值
2)該變量沒有包含在具有其他變量的不變式中
實際上,這些條件表明,可以被寫入 volatile 變量的這些有效值獨立於任何程序的狀態,包括變量的當前狀態。
事實上,我的理解就是上面的2個條件需要保證操作是原子性操作,才能保證使用volatile關鍵字的程序在併發時能夠正確執行。
下面列舉幾個Java中使用volatile的幾個場景。
1.狀態標記量
volatile
boolean
flag =
false
;
while
(!flag){
doSomething();
}
public
void
setFlag() {
flag =
true
;
}
volatileboolean
inited =
false
;
//線程1:
context = loadContext();
inited =
true
;
//線程2:
while
(!inited ){
sleep()
}
doSomethingwithconfig(context);
2.double check
class
Singleton{
private
volatile
static
Singleton instance =
null
;
private
Singleton() {
}
public
static
Singleton getInstance() {
if
(instance==
null
) {
synchronized
(Singleton.
class
) {
if
(instance==
null
)
instance =
new
Singleton();
}
}
return
instance;
}
}
出處:http://www.cnblogs.com/dolphin0520/ 作者:海子
本博客中未標明轉載的文章歸作者海子和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。