final域的重排序規則

2021-10-21 17:32:24 字數 1104 閱讀 7843

對於final 域,編譯器和處理器要遵守兩個重排序規則:

在建構函式內對乙個 final 域的寫入,與隨後把這個被構造物件的引用賦值給乙個引用變數,這兩個操作之間不能重排序。

初次讀乙個包含 final 域的物件的引用,與隨後初次讀這個 final 域,這兩個操作之間不能重排序。

public class finalexample 

public static void writer ()

public static void reader ()

}

非標準理解就是:

1.物件建構函式內有final域,必須先用建構函式構造物件,再把物件賦給其他引用

2.如果物件有final域,必須先讀物件的引用,再讀final域

寫 final 域的重排序規則可以確保:在引用變數為任意執行緒可見之前,該引用變數指向的物件的 final 域已經在建構函式中被正確初始化過了。

final引用從建構函式中「溢位」

public class finalreferenceescapeexample 

public static void writer()

public static void reader

}}

假設乙個執行緒 a 執行 writer() 方法,另乙個執行緒 b 執行 reader() 方法。這裡的操作2使得物件還未完成構造前就為執行緒 b 可見。即使這裡的操作 2 是建構函式的最後一步,且即使在程式中操作 2 排在操作 1 後面,執行 read() 方法的執行緒仍然可能無法看到 final 域被初始化後的值,因為這裡的操作 1 和操作 2 之間可能被重排序。實際的執行時序可能如下圖所示:

從上圖我們可以看出:在建構函式返回前,被構造物件的引用不能為其他執行緒可見,因為此時的 final 域可能還沒有被初始化。在建構函式返回後,任意執行緒都將保證能看到 final 域正確初始化之後的值。

final域的重排序規則

對於final 域,編譯器和處理器要遵守兩個重排序規則 在建構函式內對乙個 final 域的寫入,與隨後把這個被構造物件的引用賦值給乙個引用變數,這兩個操作之間不能重排序。初次讀乙個包含 final 域的物件的引用,與隨後初次讀這個 final 域,這兩個操作之間不能重排序。public class...

final域的記憶體語義

對於final域,編譯器和處理器要遵守兩個重排序規則。1,在建構函式內對乙個final域的寫入,與隨後把這個被構造物件的引用賦值給乙個引用變數,這兩個操作之間不能重排序。2,初次讀入乙個包含final域的物件的引用,與隨後初次讀這個final域,這兩個操作之間不能重排序。寫final域的重排序規則 ...

JVM的重排序

重排序通常是編譯器或執行時環境為了優化程式效能而採取的對指令進行重新排序執行的一種手段。重排序分為兩類 編譯期重排序和執行期重排序,分別對應編譯時和執行時環境。在併發程式中,程式設計師會特別關注不同程序或執行緒之間的資料同步,特別是多個執行緒同時修改同一變數時,必須採取可靠的同步或其它措施保障資料被...