JMM(JAVA記憶體模型) - 先行發生原則
本文中需要的基礎知識:指令重排
執行緒中兩個非常重要的問題就是:原子性與可見性.
而下面的先行發生原則就是用來解決可見性問題的.
先行發生原則--是判斷是否存在資料競爭、執行緒是否安全的主要依據。
先行發生是Java記憶體模型中定義的兩項操作之間的偏序關係。如果說操作A先行發生於操作B,其實就是說在發生操作B之前,操作A產生的影響被操作B察覺。
以下面的一段虛擬碼為例:
//以下操作線上程A中執行
int i = 1;
//以下操作線上程B中執行
j = i;
//以下操作線上程C中執行
i = 2
由於執行緒執行的先後順序不同,會導致最後j 的結果出現差異。若使執行緒安全,那麼A先行發生B,B先行發生C。
執行緒B可能獲取的是一些過期的資料。故執行緒不安全!
但是在Java記憶體模型中確實存在一些已經存在的先行發生關係,這些先行發生關係不需要任何的同步操作,就可以保證其執行緒安全!
1、程式次序規則。在一個執行緒內,書寫在前面的程式碼先行發生於後面的。確切地說應該是,按照程式的控制流順序,因為存在一些分支結構。
2、Volatile變數規則。對一個volatile修飾的變數,對他的寫操作先行發生於讀操作。
3、執行緒啟動規則。Thread物件的start()方法先行發生於此執行緒的每一個動作。
4、執行緒終止規則。執行緒的所有操作都先行發生於對此執行緒的終止檢測。
5、執行緒中斷規則。對執行緒interrupt()方法的呼叫先行發生於被中斷執行緒的程式碼所檢測到的中斷事件。
6、物件終止規則。一個物件的初始化完成(建構函式之行結束)先行發生於發的finilize()方法的開始。
7、傳遞性。A先行發生B,B先行發生C,那麼,A先行發生C。
8、管程鎖定規則。一個unlock操作先行發生於後面對同一個鎖的lock操作。
以上就是Java無需任何的同步手段就能成立的先行發生規則。其他情況下就沒有順序保障,虛擬機器可以對它們隨意地進行重排序。
總結:
happens-before指的是前面發生的操作的結構對於後面的操作的結果都是可見的,而在真正操作中並不一定前面的操作就先進行.
執行E的時候,E是不是保證看見C呢?
由法則1,hb(D,E)
由法則8,hb(B,D)
綜上可以推出,hb(A, E),但是推不出hb(C, E)
所以,E不一定能看見C,但是E一定能看見A,所以執行E的時候,有可能thread2看到的x的值還是1