2/20/2014
4:48:00 PM 0

Java Volatile

在 Java 多執行緒的環境中 synchronized 是相當常用的關鍵字之一,使用 synchronized 有兩個效果 mutex & visibility
mutex 主要目的是建立 critical section, 而 visibility 的作用是保持記憶體的一致性(memory consistency)

什麼是記憶體一致性呢? 我們知道一般物件是擺在記憶體內的,如果要對物件資料做運算,CPU 通常會將要做運算的資料複製一份到 CPU 的 register 加快處理速度,而運算完的資料有時並不會立刻寫回主記憶體,而是留在 register 內,在多執行緒的環境下,如果此時另一個 CPU 來讀取同一份資料就會產生記憶體不一致的問題,因此 Java 定義了 volatile 關鍵字來處理記憶體資料一致性的問題

Java Language Specification 對 volatile 的定義

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
  1. status flags
  2. one-time safe publication
  3. independent observations
  4. volatile bean
  5. The cheap read-write lock trick
使用 volatile 可獲得比使用鎖更高的執行效率,例如在讀取動作遠遠大於寫入動作的狀況下,就非常適合使用 volatile,但如果對於 volatile 用法不是很熟悉,使用鎖是比較不容易出錯的方法

參考 : http://www.ibm.com/developerworks/library/j-jtp06197

0 comments:

Post a Comment