新的Java內存模型在內存操做(讀字段,寫字段,lock,unlock)和線程操做(start,join)之間定義了順序,叫作一種操做 happens before 其餘操做。當一種操做happens before另一種操做時,第一個操做被確保在第二個操做以前執行,並且操做內容對第二個操做可見。具體規則以下:
單線程裏面每一個操做 happens before 代碼裏面此操做後面的操做
對一個monitor的unlock操做 happens before 在 這個monitor 上全部後續的lock操做
對一個volatile字段的寫入 happens before 對 這個字段 的全部後續讀操做
對一個線程的start操做 happens before 此啓動線程裏面的任何操做
對一個線程使用join操做,被join線程裏面的任何操做 happens before join() 調用的返回
因此,若是對一個monitor進行同步,全部釋放monitor前的操做都對後續獲取monitor的線程可見。由於全部的內存操做 happens before 所釋放, 鎖釋放 happens before 接下來的鎖獲取。
P.S. Rule1特別解釋:
rule1定義了單線程裏面全部操做都是按照代碼順序執行的,那是否是就不會產生重排序了?由於重排序後就跟代碼順序不同了。答案是,No,仍然會重排序 。具體能夠參考stackoverflow連接 重排序與happens before
It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation. If the reordering produces results consistent with a legal execution, it is not illegal.
final是怎麼樣工做的
只要對象是被 正確的構造 的,只要這個對象構造完成,賦值給final字段的值即便沒有同步機制,對其餘全部的線程也是可見的。即便final字段是其餘對象或數組的引用,這些引用值也至少跟final字段同樣是 up to date as of the end of the object's constructor 。
Volatile是用來線程間交換狀態特殊關鍵字。每次 volatile 讀都會讀到其餘任何線程上次寫入的值。每次寫入後,都會刷入內存。每次讀取前,也會失效本地緩存,直接從內存讀取。除此以外,還有特殊的限制,跟老的內存模型不一樣,新的內存模型不容許在volatile字段先後進行指令重排序。當線程 A 在寫 volatile 字段 f 前全部可見的字段都會線程 B 讀取 f 時可見。
舉例:
classVolatileExample{
int x = 0;
volatileboolean v = false;
publicvoidwriter(){
x = 42;
v = true;
}
publicvoidreader(){
if (v == true) {
//uses x - guaranteed to see 42.
}
}
}
複製代碼