最終フィールドへの読み書きは、通常の変数アクセスのように見えます。
finalドメインの並べ替えルール
最終ドメインでは、コンパイラとプロセッサは2つの並べ替えルールに従います。
- コンストラクタ内の最終ドメインへの書き込みと、その後にこの構築されたオブジェクトへの参照を参照変数に代入する間に、順序を入れ替えることはできません。
- 最終フィールドを含むオブジェクトへの参照の最初の読み取りと、それに続くその最終フィールドの最初の読み取りとの間で、順序を入れ替えることはできません。
コード例
public class FinalExample {
int i; // 共通変数
final int j; // final
static FinalExample obj;
public FinalExample() { // コンストラクタ
i = 1; // 正規ドメインの記述
j = 2; // 最終フィールドの記述
}
public static void writer() { // スレッドAの実行を書く
obj = new FinalExample();
}
public static void reader() { // スレッドBの実行を読む
FinalExample object = obj; // オブジェクト参照の読み込み
int a = object.i; // 共通フィールドを読む
int b = object.j; // 最終フィールドを読む
System.out.println("a: " + a); // 0を見ることができる
System.out.println("b: " + b); // 2を見ることを保証する
}
}
ここで、スレッドAがwriter()メソッドを実行し、その後に別のスレッドBがreader()メソッドを実行したとします。
最終フィールドの並べ替えルールの記述
最終フィールドへの書き込みの並べ替えルールでは、コンストラクタ以外での最終フィールドへの書き込みの並べ替えを禁止しています。このルールの実装は、以下の2つの側面から構成されています。
- JMMは、コンパイラがコンストラクタの外部で最終フィールドへの書き込みを並べ替えることを禁止しています。
- コンパイラは、最終ドメインの書き込み、コンストラクタのリターンの後に StoreStore バリアを挿入します。このバリアは、プロセッサがコンストラクタの外部で最終フィールドの書き込みの順序を変更することを禁止します。
次にwriter()メソッドを分析します。
obj = new FinalExample();
このコードには2つのステップがあります。
- FinalExample型のオブジェクトを構築します。
- このオブジェクトへの参照を参照オブジェクト obj に割り当てます。
スレッド B がオブジェクトの参照を読み取るときと、オブジェクトのメンバ・フィールドを読み取るときとで、順序の入れ替えがないと仮定します。次の図は、実行順序の1つの可能性を示しています。
図からわかるように、通常ドメインを書き込む操作は、コンストラクタの外側でコンパイラによって並び替えが行われ、スレッドBは通常変数iの初期化された値を誤って読み取ります。最終ドメインを書き込む操作は、最終ドメインを書き込むという並び替えによってコンストラクタに限定され、読み込まれたスレッドBは初期化された後の最終変数の値を正しく読み取ります。
最終的な領域の並べ替えの要約を書く
最終ドメインを記述するための並べ替えルールは、オブジェクト参照がどのスレッドからも見えるときに、オブジェクトの最終ドメインが正しく初期化されていることを保証します。
最終フィールドの並び替えルールを読む
最終フィールドの読み取りに関する並べ替えルールは、スレッド内のオブジェクト参照の最初の読み取りと、そのオブジェクトに含まれる最終フィールドの最初の読み取りが同じであるというもので、JMMはプロセッサが両方の操作を並べ替えることを禁止しています。コンパイラは、最終フィールドの読み取り操作の前に LoadLoad バリアを挿入します。これは、これら 2 つの操作の間に間接的な依存関係があるためです。コンパイラは間接的な依存関係に従うため、これら 2 つの操作の順序を変更することはありません。コードによると、reade() メソッドには 3 つの操作があります。
- 初期読み込み参照変数 obj.
- 最初の読み取り参照変数objは、オブジェクトの共通ドメインjを指します。
- 参照変数objの最初の読み込みは、オブジェクトの最終ドメインiを指します。
最終フィールドの並べ替えの概要を読む
最終ドメインを読み取るオブジェクトを読み取る場合、この最終ドメインを含むオブジェ クトへの参照が最初に読み取られなければなりません。参照が NULL でない場合、参照されたオブジェクトの最終ドメインはスレッド A によってすでに初期化されていなければなりません。
スタディー・ソース The Art of Concurrent Programming in Java
個人的な意見です。議論すること自由に感じなさい、個人ブログ