2010-10-19 65 views
12

之前發生了,我有兩個線程:volatile變量和訂購

主題:1

a = 1; 
x = b; 

主題:2

b = 1 
y = a 

這裏a和b聲明爲volatile。我不明白在a = 1;之間如何創建「發生之前」邊緣;和y = a;和x = b之間;和b = 1;

我明白,通過使用volatile變量,可以防止從線程緩存讀取陳舊值。但是,如何確保在訂購之前發生易失變量。

具體來說,我不明白這一點:

到揮發性現場寫的 同一領域的每一個後續讀之前發生 。

鋤頭能行嗎?

+0

看到這個最近的問題和答案的很多相關的信息:http://stackoverflow.com/questions/3964317/memory-barriers-and-coding-style-over-a-java-vm – andersoj 2010-10-19 18:43:36

回答

15

寫入易失性字段發生在每次後續讀取相同字段之前。

這裏重要的詞是「後續」。

這裏的Java語言規範17.4.4 Synchronization Order的相關位:

每次執行具有同步順序。同步順序是執行的所有同步操作的總順序。對於每個線程t,t中同步動作(第17.4.2節)的同步順序與t的程序順序(第17.4.3節)一致。 同步動作誘導同步-與動作關係,定義如下:

  • [...]
  • 於揮發性變量A寫(§8.3.1.4)V同步-與所有後續讀取的v由任何線程(其中隨後根據同步順序定義)。

請注意最後一部分。所以這就是說,如果考慮程序行爲的任何總排序,任何在整個排序中寫入的易失性變量的讀取都不會「錯過」寫入。

+0

「*對於每個線程t *,同步動作的同步順序...「易變本身並不決定線程之間的同步順序嗎? – 2010-10-19 17:47:54

+0

我也有同樣的問題。發現java spec有點神祕。 – devnull 2010-10-19 18:04:59

+1

@pst:易失性操作* total *順序,而不是特定線程的順序。它實際上意味着一個線程無法讀取一個volatile變量而不檢查其他線程是否執行了寫操作。 – 2010-10-19 18:21:01

3

對易失性字段的寫入發生在每個後續讀取同一字段之前。

這段文字是令人困惑的。它限制了發生之前發生的事情 - 在讀之前!它只是說,讀取之後發生,實際上發生在之後。

換句話說,它試圖說的是,在寫入過程中,讀取不會發生,並且如果還有其他發生 - 在寫入之後導致讀取發生的關係之前,讀取將具有該寫入的值。

請參閱JLS部分17.4.4 Synchronization Order,它在此上下文中定義單詞「後續」。

3

要分析,首先列出所有可能的同步順序。他們必須符合編程順序。在你的例子中,有6個可能的訂單。

1  2  3  4  5  6 
w(a) w(a) w(b) w(a) w(b) w(b) 
r(b) w(b) w(a) w(b) w(a) r(a) 
w(b) r(b) r(b) r(a) r(a) w(a) 
r(a) r(a) r(a) r(b) r(b) r(b) 

每個訂單建立一些發生之前的關係。在(1)中,我們有w(a)發生在r(a)之前。在(6)中,我們有w(b)發生在r(b)之前。在(2) - (5)中,我們都有。

對於每一個可能的訂單,考慮到由它建立之前發生的關係,你需要分析執行,以確保它做你想做的。

如果這聽起來太難了,它是。在現實生活中,我們通常僅限於簡單的情況,其中只有一個對象被鎖定/釋放,或者只有一個易失性變量被讀取和寫入。然後它不是太複雜。