分三個層次吧:
第一層次:單個對象或單個方法層次
a.程序次序規則:可以理解爲某一線程中的run方法執行代碼,控制流書寫在前的一定先行於書寫在後的,當然,是廣義的書寫,考慮循環及判斷
b.管程鎖定規則:可以理解爲被鎖的(比如synchronized鎖定的)程序塊中,執行時間在前的先行於執行時間在後的
c.volatile規則:對一個volatile的寫執行先行於時間上位於後面的對這個變量的讀操作
d.對象的構造方法先行於finalize的開始
注意:a指的是書寫次序、b和c指的是時間次序,這個是不一樣的,a指單線程內,而b和c可以看作不同線程內執行的時間前後
第二層次:線程層次:
e.線程啓動先行於線程內的執行
f.線程執行先行於線程終止
g.對線程interrupt()方法的調用先行於中斷事件的發生
第三個層次:傳遞原則:
若A先行於B,B先行於C,則A先行於C
符合先行發生關係的邏輯由系統保證多線程的邏輯同步,不需要自己控制
有一個注意點:先行發生關係並不是CPU指令集上的前後順序,或者說並非實際執行的先後順序。怎麼理解呢?符合先行發生關係的邏輯:A先行於B,以Java爲例,JVM保證若B用到了A的數值或結果,則該數值或結果,A一定先行於B,若A、B並無必然的聯繫,從JVM層面,A、B甚至是可以互換的。再舉一個例子可能更好理解一些:代碼的書寫次序:
{
int a = 1; //A
int b = 2; //B
int c = a + b; //C
}
A先行於C,B也先行於C,A、B並無必然的次序,在字節碼層面,執行的次序可能爲A->B->C,也可能是B->A->C
在理想的內存模型中,一定是A->B->C,但JVM爲了運行優化,可能會對A、B進行交換。
有一個辦法可以阻止A、B換位:volatile關鍵字--被volatile修飾的變量,讀不與前交換,寫不與後交換
在單線程的環境下,A、B換位並不會影響程序運行結果,而在多線程的環境下,因A、B換位可能會引發一些非所期望的結果,要加倍關注。