2010-03-31 54 views
3

考慮下面的Java代碼:!不同!易變的變量?

volatile boolean v1 = false; 
volatile boolean v2 = false; 

//Thread A 
v1 = true; 
if (v2) 
    System.out.println("v2 was true"); 

//Thread B 
v2 = true; 
if (v1) 
    System.out.println("v1 was true"); 

如果有揮發性訪問全局可見總訂貨則至少有一個的println總是到達。

這實際上是由Java標準保證的嗎?或者是這樣的可能執行:

A: v1 = true; 
B: v2 = true; 
A: read v2 = false; 
B: read v1 = false; 
A: v2 = true becomes visible (after the if) 
B: v1 = true becomes visible (after the if) 

我只能找到報表有關訪問的標準相同 volatile變量(但我可能失去了一些東西)。

「寫入易失性變量(§8.3.1.4)v與任何線程(隨後根據同步順序定義的內容)隨後對v的所有後續讀取進行同步。」

http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4.4

謝謝!

+0

是的,它的確如此。這個問題是http://stackoverflow.com/questions/2441279/java-volatile-guarantees-and-out-of-order-execution的副本 – 2010-03-31 18:33:47

回答

1

我認爲報價回答您的問題比你更認識它。

在線#2中線程Bv2的寫入在嘗試讀取變量時由線程A「看到」。

我加粗報價的關鍵部分:

「到volatile變量的寫(§8.3.1.4)V同步所有後續的任何線程讀取訴...「

+0

@matt b:是的,但它比這更復雜:如果在線程A中發生重新排序,該怎麼辦? (看起來我的回答是真正的評論)。我認爲在這種情況下重新排序是非法的......但是這句話當然沒有多說這些。 – SyntaxT3rr0r 2010-03-31 19:28:18

+0

重新排序哪些語句?通常「重新排序」適用於在方法或代碼塊內對語句進行重新排序以改變操作順序。 JVM只允許重新排列不會影響後續語句的語句。在你的線程中,唯一需要重新排序的是賦值和對另一個變量的檢查 - 在線程run()中重新排序這兩個語句不會影響任何內容。 – 2010-03-31 19:32:44

0

由於v2volatile這一事實,執行中的第三行是不可能的。

如果v2不是volatile,線程A可以看到v2的本地緩存副本,該副本仍然是false

由於v2是易失性的,但是,每次讀取都會直接進入主存儲器,因此會看到最近寫入的值。這就是說,我不相信在訪問不同的全局變量之間有任何特定的順序保證,但我也不相信這會對你的例子產生影響。

-1

那麼......如果v2被B設置爲true,那麼通過volatile的定義,那麼A就不能將其讀爲false。

揮發性使得數據類型和引用線程工作時做單opeartions時如預期(所以++和 - !不工作)

+1

這也適用於64位長的 – 2010-03-31 20:19:00

+0

你是對的:http: //mindprod.com/jgloss/volatile。html在Java 1.5中進行了更改 – Pyrolistical 2010-03-31 22:02:32

-1

這太長評論(這只是一個可能的重新排序的情況下注釋),但我認爲以下是可能如果你只有一個線程

A: read v2 = false; 
A: v1 = true; 

的」閱讀「(如果)可以在作業前發生(如果它對接下來的內容沒有影響)。 10以下不能發生:

A: read v2 = false; 
A: v1 = true; 
B: read v1 = false; 
B: v2 = true; 

這是不可能的,因爲你有兩個線程,因此這些線的人可能檢測出重排有這樣的重新排序,使得該編譯器重新排序非法的。

我在這裏問類似,但絕對不相同的一個問題(在同一個線程寫a和b,從不同的線程讀取):

Volatile guarantees and out-of-order execution

1

4分的動作,V1的揮發性讀/寫/ v2,都是同步操作。執行對它們有一個同步順序,這是一個總的順序。訂單必須保持每個線程的程序順序。

這使得推理非常簡單。顯然,至少對於2個變量中的1個,在'同步順序'中對它的寫入是在讀取它之前進行排序的。因此,寫入'與'同步'讀取。因此,寫入'發生在'讀取之前。因此,寫入對讀取是可見的。

0

簡而言之:至少會打印一次,因爲兩個易失性操作不能重新排序。

我不知道它在說明書中寫的是什麼,但在Doug Lea網站上有一個表格,哪些操作可以重新排序,哪些不可以。 (http://gee.cs.oswego.edu/dl/jmm/cookbook.html


這種情況是不可能的,因爲讀是初始化發生之前線程開始

錯了!

A: v1 = true; 
B: v2 = true; 
A: read v2 = false; // initialization happens before thread start 
B: read v1 = false; // initialization happens before thread start 

您的情況可能的,如果只有在這種情況下,這是不可能的,因爲v2和V1是易失性寫V1必須閱讀之前V2寫V2前必須讀取v1

錯誤!

volatile boolean v1 = false; 
volatile boolean v2 = false; 

//Thread A 
if (v2) //read v2 
    System.out.println("v2 was true"); 
v1 = true; //write to v1 

//Thread B 
if (v1) //read v1 
    System.out.println("v1 was true"); 
v2 = true; //write v2