blog

JAVAコンカレント(8)最終フィールド

最終領域への読み書きは通常の変数アクセスのように見えます。 コンパイラとプロセッサが最終ドメインに対して従う並べ替えルールには2つあります。 コンストラクタ内の最終ドメインへの書き込みと、その後にこの...

Jul 11, 2020 · 3 min. read
シェア

最終フィールドへの読み書きは、通常の変数アクセスのように見えます。

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つの側面から構成されています。

  1. JMMは、コンパイラがコンストラクタの外部で最終フィールドへの書き込みを並べ替えることを禁止しています。
  2. コンパイラは、最終ドメインの書き込み、コンストラクタのリターンの後に StoreStore バリアを挿入します。このバリアは、プロセッサがコンストラクタの外部で最終フィールドの書き込みの順序を変更することを禁止します。

次にwriter()メソッドを分析します。

obj = new FinalExample();

このコードには2つのステップがあります。

  1. FinalExample型のオブジェクトを構築します。
  2. このオブジェクトへの参照を参照オブジェクト obj に割り当てます。

スレッド B がオブジェクトの参照を読み取るときと、オブジェクトのメンバ・フィールドを読み取るときとで、順序の入れ替えがないと仮定します。次の図は、実行順序の1つの可能性を示しています。

図からわかるように、通常ドメインを書き込む操作は、コンストラクタの外側でコンパイラによって並び替えが行われ、スレッドBは通常変数iの初期化された値を誤って読み取ります。最終ドメインを書き込む操作は、最終ドメインを書き込むという並び替えによってコンストラクタに限定され、読み込まれたスレッドBは初期化された後の最終変数の値を正しく読み取ります。

最終的な領域の並べ替えの要約を書く

最終ドメインを記述するための並べ替えルールは、オブジェクト参照がどのスレッドからも見えるときに、オブジェクトの最終ドメインが正しく初期化されていることを保証します

最終フィールドの並び替えルールを読む

最終フィールドの読み取りに関する並べ替えルールは、スレッド内のオブジェクト参照の最初の読み取りとそのオブジェクトに含まれる最終フィールドの最初の読み取りが同じあるというもので、JMMはプロセッサが両方の操作を並べ替えることを禁止しています。コンパイラは、最終フィールドの読み取り操作の前に LoadLoad バリアを挿入します。これは、これら 2 つの操作の間に間接的な依存関係があるためです。コンパイラは間接的な依存関係に従うため、これら 2 つの操作の順序を変更することはありません。コードによると、reade() メソッドには 3 つの操作があります。

  1. 初期読み込み参照変数 obj.
  2. 最初の読み取り参照変数objは、オブジェクトの共通ドメインjを指します。
  3. 参照変数objの最初の読み込みは、オブジェクトの最終ドメインiを指します。

最終フィールドの並べ替えの概要を読む

最終ドメインを読み取るオブジェクトを読み取る場合、この最終ドメインを含むオブジェ クトへの参照が最初に読み取られなければなりません。参照が NULL でない場合、参照されたオブジェクトの最終ドメインはスレッド A によってすでに初期化されていなければなりません。

スタディー・ソース The Art of Concurrent Programming in Java

個人的な意見です。議論すること自由に感じなさい、個人ブログ

JAVAにおける並行プログラミングの課題

JAVA並行同期および揮発性の基本実装原則

JAVA並行ロック状態

JAVA並行アトミック演算実装原理

JAVA同時実行の前に起こること

Read next

Eurekaアクティブ・オフライン・サービス

をフックに加えることで、サービスを直接停止することができます。 デフォルトでは、Eureka Serverは90秒以内にEurekaクライアントから更新を受け取らなかった場合、インスタンスをレジストリから削除します。しかし、この方法の悪い点は、クライアントの実行が停止しているにもかかわらず、レジストリにリストされたままになっていることです。 特定のロードバランシングポリシーやヒューズを使用することで、サービスを継続させることは可能ですが、レジストリを...

Jul 10, 2020 · 2 min read

nginxの設定 wss

Jul 10, 2020 · 2 min read

島の数

Jul 10, 2020 · 2 min read

Javaアノテーションの詳細

Jul 8, 2020 · 2 min read