2014-10-05 29 views
0

這個Q正在尋找關於Java如何使volatile字段可見的具體細節。Java如何管理易失性字段的可見性?

Java中的volatile關鍵字用於在完成對其的寫入操作後,使該變量的讀者「主動」可見的變量。這是發生之前關係的一種形式 - 使得寫入結果暴露給訪問該變量的內存位置以供某些用途的人。並且在使用時,對該變量進行讀/寫操作原子 - 對於long & double - 對於其他所有var類型的R/W已經是原子。

我期待找出Java那樣做一個變量的值寫入操作後看到什麼呢?

例如:下面的代碼是從this討論其中一個答案:

public class Foo extends Thread { 
    private volatile boolean close = false; 
    public void run() { 
    while(!close) { 
     // do work 
    } 
    } 
    public void close() { 
    close = true; 
    // interrupt here if needed 
    } 
} 

讀取和刻錄布爾文字是原子。如果調用上述方法close(),它是一個原子操作來設置的close值作爲true即使未聲明爲volatile

更何況volatile在此代碼做的是確保更改這個值被認爲是它發生的那一刻。

究竟如何volatile是實現這一目標?

通過對volatile變量優先與操作的線程?如果是這樣 - 在線程調度中如何執行,或者通過使讀取操作的線程查找標誌來查看是否有寫入器線程掛起?我知道「寫入一個易失性字段發生在每次後續讀取該字段之前」。它是否在線程中進行選擇,在給只讀的線程提供CPU時間之前,它對volatile變量有一個寫操作?

如果這是在線程調度級別(我懷疑)中進行管理,那麼在易失性字段上運行寫入線程會比看起來效果更大。

究竟是如何被管理的Java變量volatile的知名度?

TIA。

+1

它保證一個線程寫入到volatile變量將寫入主存儲器,並而不是處理器緩存,並且讀取volatile變量值的線程不會從處理器緩存中讀取,而是從主存儲器中讀取。我不是這些低級硬件機制的專家, LL讓專家回答,但你應該明白我的意思,與調度或優先級無關。 – 2014-10-05 16:55:37

+0

的CPU完成所有的工作。在JVM確保它使用了正確的指示。 – 2014-10-05 17:36:01

回答

2

這是OpenJDK的源代碼約揮發性

// ---------------------------------------------------------------------------- 
// Volatile variables demand their effects be made known to all CPU's 
// in order. Store buffers on most chips allow reads & writes to 
// reorder; the JMM's ReadAfterWrite.java test fails in -Xint mode 
// without some kind of memory barrier (i.e., it's not sufficient that 
// the interpreter does not reorder volatile references, the hardware 
// also must not reorder them). 
// 
// According to the new Java Memory Model (JMM): 
// (1) All volatiles are serialized wrt to each other. ALSO reads & 
//  writes act as aquire & release, so: 
// (2) A read cannot let unrelated NON-volatile memory refs that 
//  happen after the read float up to before the read. It's OK for 
//  non-volatile memory refs that happen before the volatile read to 
//  float down below it. 
// (3) Similar a volatile write cannot let unrelated NON-volatile 
//  memory refs that happen BEFORE the write float down to after the 
//  write. It's OK for non-volatile memory refs that happen after the 
//  volatile write to float up before it. 
// 
// We only put in barriers around volatile refs (they are expensive), 
// not _between_ memory refs (that would require us to track the 
// flavor of the previous memory refs). Requirements (2) and (3) 
// require some barriers before volatile stores and after volatile 
// loads. 

我希望這是有幫助的評論。

+0

你從哪兒 – Roam 2014-10-05 17:07:23

+0

@Roam得到這個,我與[OpenJDK](http://openjdk.java.net/)的來源以及[hotspot's]的這條評論一起工作(http://en.wikipedia.org/wiki/HotSpo t)口譯員P.S.隨時糾正我的英語 – Kastaneda 2014-10-05 17:31:02

+0

他們通常提供鏈接到一個來源在這裏。通過它,如果不是祕密或任何東西 – Roam 2014-10-05 18:15:31

2

根據此:

http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile

Java的新的內存模型由

1做到這一點)從寄存器分配volatile變量禁止編譯器和運行。

2)不允許編譯器/優化器從代碼重新排序字段訪問。實際上,這就像獲得一個鎖。

3)強制編譯器/運行時只要它被寫入刷新從高速緩存的易失性可變到主存儲器中。

4)在讀取易失性字段之前將高速緩存標記爲無效。

從文章:。

「揮發性字段被用於線程間通信狀態的揮發性的每次讀會被任何線程看到最後寫入該揮發性特殊領域;實際上,他們被指定由程序員將其視爲字段,因爲緩存或重新排序的結果是看不到「過時的」值,編譯器和運行時間禁止在寄存器中分配它們,還必須確保寫入後它們是同時,在讀取一個易失性字段之前,必須使緩存失效,以便主內存中的值(而不是本地處理器緩存)是唯一的值看到。還有另外一個l對重新排序訪問volatile變量的限制。 「

... 」寫入易失性字段與監視器版本具有相同的記憶效應,並且從易失性字段讀取具有與監視器獲取相同的記憶效應。實際上,因爲新的內存模型放在揮發性場的重新排序嚴格限制訪問與其他字段訪問,揮發或不...」

+0

很好的答案+1。只需編輯第一個單詞,寫下「根據」而不是「ccording」。 – Alboz 2014-10-06 08:11:54

+0

是的。謝謝,修復它。 – 2014-10-06 08:31:24