mutex 主要目的是建立 critical section, 而 visibility 的作用是保持記憶體的一致性(memory consistency)
什麼是記憶體一致性呢? 我們知道一般物件是擺在記憶體內的,如果要對物件資料做運算,CPU 通常會將要做運算的資料複製一份到 CPU 的 register 加快處理速度,而運算完的資料有時並不會立刻寫回主記憶體,而是留在 register 內,在多執行緒的環境下,如果此時另一個 CPU 來讀取同一份資料就會產生記憶體不一致的問題,因此 Java 定義了 volatile 關鍵字來處理記憶體資料一致性的問題
Java Language Specification 對 volatile 的定義
- A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable
- A write to a volatile field happens-before every subsequent read of that field
Java Specification 裡只定義規範, 也就是使用 volatile 之後可保證所有的 threads 看到變數的值是一致的,並沒有硬性規定如何實作,給了實作 JVM 彈性,因此實作的方式可能有很多種,譬如說如果使用 volatile 關鍵字的變數就不可對變數使用 cache memory,直接對主記憶體資料作讀寫,這也是一種方式,當然實際實作可能沒那麼簡單
引用 Java Concurrency in Practice 的範例
public class NoVisibility { private static boolean ready; private static int number; private static class ReaderThread extends Thread { public void run() { while (!ready) Thread.yield(); System.out.println(number); } } public static void main(String[] args) { new ReaderThread().start(); number = 42; ready = true; } }這個例子沒有使用 synchronized,有可能會因為記憶體不一致而造成無法預期的結果, 變數 ready 可能一直是 false, 也可能印出 0 的值,但在我的 PC 上怎麼測都測不出印出 0 的結果,正確的寫法是使用 synchronized 或使用 volatile 關鍵字, 將 ready, number 都標示為 volatile
至於在什麼狀況下可使用 volatile 呢? 可參考這篇文章 Java theory and practice: Managing volatility
- status flags
- one-time safe publication
- independent observations
- volatile bean
- The cheap read-write lock trick
參考 : http://www.ibm.com/developerworks/library/j-jtp06197
0 comments:
Post a Comment