7.final

1. final的指令重排

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

  1. 在構造函數內對一個final變量賦值,與隨後把這個被構造對象的引用賦值給一個變量,這兩個操作之間不能重排序
  2. 初次讀一個包含final變量的對象,與隨後初次讀這個final變量,這兩個操作之間不能重排序
public class FinalExample {
       int i;                    // 普通變量
       final int j;                // final 變量
       static FinalExample obj;
       public FinalExample () {          // 構造函數
              i = 1;               // 寫普通域
              j = 2;               // 寫 final 域
       }
       public static void writer () {    // 寫線程 A 執行
              obj = new FinalExample ();
       }
       public static void reader () {    // 讀線程 B 執行
              FinalExample object = obj;  // 讀對象引用
              int a = object.i;      // 讀普通域
              int b = object.j;      // 讀 final 域
       }
}

1.1. 賦值final屬性的指令重排

賦值final屬性的重排序規則禁止把final屬性的賦值操作重排序到構造函數之外,這個規則的實現包含下面2個方面

  1. JMM 禁止編譯器把 final屬性的賦值操作重排序到構造函數之外
  2. 編譯器會在 final 域的寫之後,構造函數 return 之前,插入一個 StoreStore 屏障。這個屏障禁止處理器把 final 域的寫重排序到構造函數之外

寫 final 域的重排序規則可以確保:在對象引用爲任意線程可見之前,對象的 final 域已經被正確初始化過了,而普通域不具有這個保障

1.2. 讀取final屬性的指令重排

讀 final 域的重排序規則是,在一個線程中,初次讀對象引用與初次讀該對象包含的 final 域,JMM 禁止處理器重排序這兩個操作.編譯器會在讀 final 域操作的前面插入一個 LoadLoad 屏障

1.3. final屬性爲引用類型

對於引用類型,賦值final屬性的重排序規則對編譯器和處理器增加了如下約束:
在構造函數內對一個引用類型的final屬性的賦值,與隨後在構造函數外把這個被構造對象的引用賦值給一個引用變量,這兩個操作之間不能重排序

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章