Java內存模型中的Happens-Before規則

規則

Happens-Before 約束了編譯器的優化行爲,雖然允許編譯器優化,但是要求編譯器優化後一定遵守 Happens-Before 規則

在 Java 語言裏面,Happens-Before 的語義本質上是一種可見性,A Happens-Before B意味着 A 事件對 B 事件來說是可見的,無論 A 事件和 B 事件是否發生在同一個線程裏。例如 A 事件發生在線程 1 上,B 事件發生在線程 2 上,Happens-Before 規則保證線程 2上也能看到 A 事件的發生。(參考:Java併發編程實戰)

  • 程序順序規則:一個線程中,按照程序中代碼順序,前面的操作Happens-Before於後面的操作
  • volatile變量規則:對一個volatile變量的寫操作Happens-Before於後續對該變量的讀操作
  • 傳遞性規則:如果A Happens-Before B,且B Happens-Before C,則A Happens-Before C
  • 鎖的規則:一個鎖的解鎖操作Happens-Before於該鎖後續的加鎖操作
  • 線程啓動規則:如果線程A啓動了線程B,則線程B啓動前的操作Happens-Before線程B後續的操作
  • 線程結束規則:如果線程A中調用線程B的join()方法併成功返回,則線程B中的任意操作Happens-Before於該join()操作的返回
  • 中斷規則:對線程interrupt()方法的調用Happens-Before於被中斷線程檢測到中斷方法被調用
  • 終結器規則:一個對象的構造函數執行結束Happens-Before於它的finalize()方法的開始

案例

代碼(來源:JSR 133 (Java Memory Model) FAQ

class VolatileExample {
    int x = 0;
    volatile boolean v = false;
    public void writer() {
        x = 42;
        v = true;
    }
    public void reader() {
        if (v == true) {
            //uses x - guaranteed to see 42.
        }
    }
}

根據程序順序規則可知:x = 42 Happens-Before v = true
根據volatile變量規則可知:寫volatile變量 v = true Happens-Before 讀volatile變量 v
根據傳遞性規則可知:x = 42 Happens-Before 讀volatile變量 v

代碼

// x是共享變量, 初始值爲10
int x = 10;
// synchronized中的鎖是隱式實現的,會在進入代碼塊之前自動加鎖,執行完代碼塊之後自動釋放鎖
synchronized (this) {
    if (this.x < 12) {
        this.x = 12;
    }
}

根據鎖的規則可知:線程A執行完代碼塊之後的解鎖操作Happens-Before線程B進入代碼塊之前的加鎖操作,因此線程B進入代碼塊時可知x=12

代碼

// x是共享變量, 初始值爲10
int x = 10;

Thread threadB = new Thread(() -> {
    System.out.println("線程B可以看到x的值爲:" + x);
    // 線程B將共享變量x的值改爲21
    x = 21;
});
x = 12;
// 線程A中啓動線程B
threadB.start();
threadB.join();
System.out.println("線程A可以看到x的值爲:" + x);

根據線程啓動規則可知:x = 12 Happens-Before threadB.start(),因此線程B啓動後可以看到x被修改爲12
根據線程結束規則可知:x = 21 Happens-Before threadB.join() ,因此主線程可以看到線程B結束前的任意操作,即將x修改爲21

總結

Java併發編程中有三個核心問題:可見性、有序性和原子性,其中可見性和有序性便是由 Happens-Before 規則保證的

補充

Java併發編程中的三個核心問題是怎麼產生的?

參考

JSR 133 (Java Memory Model) FAQ
Java併發編程實戰

發佈了22 篇原創文章 · 獲贊 17 · 訪問量 848
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章