web-dev-qa-db-ja.com

javaでの命令の並べ替えと発生前の関係

本の中でJava並行性実際には、コンパイラー、実行時のJVM、またはプロセッサーによってプログラムの命令を並べ替えることができると何度か言われています。実行されたプログラムは、ソースコードで指定した順序とまったく同じ順序で命令が実行されないことを前提としています。

ただし、Javaメモリモデルについての最後の章では、JVMが保持する命令の順序を示すhappens-beforeルールのリストを提供します。これらのルールの最初のルールは次のとおりです。

  • 「プログラム順序規則。スレッド内の各アクションは、プログラム順序で後に来るそのスレッド内のすべてのアクションの前に発生します。」

「プログラムの順序」とはソースコードを指していると思います。

私の質問:このルールを前提として、どの命令が実際に並べ替えられるのかと思います。

「アクション」は次のように定義されます。

Javaメモリモデルは、変数の読み取りと書き込み、モニターのロックとロック解除、スレッドの開始と結合などのアクションに関して指定されます。JMMは、発生する前に発生する部分的な順序付けを定義しますプログラム内のすべてのアクションで実行されます。アクションBを実行するスレッドがアクションAの結果を確実に表示できるようにするには(AとBが異なるスレッドで発生するかどうか)、AとBの関係の前に発生する必要があります。 2つの操作間で注文する前に発生する場合、JVMは自由にそれらを自由に再注文できます。

言及されている他の注文ルールは次のとおりです。

  • ロック規則を監視します。モニターロックのロック解除は、同じモニターロックの後続のすべてのロックの前に発生します。
  • 揮発性変数のルール。揮発性フィールドへの書き込みは、同じフィールドの後続のすべての読み取りの前に行われます。
  • スレッド開始ルール。スレッドでのThread.startの呼び出しは、開始されたスレッドのすべてのアクションの前に発生します。
  • スレッド終了規則。スレッド内のアクションは、他のスレッドがスレッドの終了を検出する前に、Thread.joinから正常に戻るか、Thread.isAliveがfalseを返すことによって発生します。
  • 中断ルール。別のスレッドで割り込みを呼び出すスレッドは、割り込みを受けたスレッドが割り込みを検出する前に発生します(InterruptedExceptionがスローされるか、isInterruptedまたは割り込みが呼び出されます)。
  • ファイナライザルール。オブジェクトのコンストラクタの終了は、そのオブジェクトのファイナライザの開始前に発生します。
  • 推移性。 AがBの前に発生し、BがCの前に発生する場合、AはCの前に発生します。
53
Martin

プログラムの順序ルールの要点は、スレッド内です。

この単純なプログラムを想像してみてください(最初はすべての変数が0):

T1:

_x = 5;
y = 6;
_

T2:

_if (y == 6) System.out.println(x);
_

T1の観点から見ると、実行はx(プログラムの順序)の後にyが割り当てられることと一致している必要があります。ただし、T2の観点からは、これはそうである必要はなく、T2は0を出力する可能性があります。

2つの割り当ては独立しており、それらをスワップしてもT1の実行に影響を与えないため、T1は実際に最初にyを割り当てることができます。

適切に同期すると、T2は常に5または何も印刷しません。

[〜#〜]編集[〜#〜]

プログラムの順序の意味を誤解しているようです。 プログラムの順序ルールは次のように要約されます

xyが同じスレッドのアクションであり、xがプログラムの順序でyの前にある場合、hb(x, y)(つまりxhappens-beforey)。

happens-beforeは、JMMで非常に具体的な意味を持っています。特に、それはnotを意味し、_y=6_は壁時計の観点からT1の_x=5_の後にある必要があることを意味します。これは、T1によって実行される一連のアクションが一貫性があるの順序でなければならないことを意味するだけです。 JLS 17.4.5 も参照できます。

2つのアクションの前に発生する関係の存在は、必ずしも実装でこの順序で発生する必要があることを意味するわけではないことに注意してください 。並べ替えが合法的な実行と一致する結果を生成する場合、それは違法ではありません。

上記で示した例では、T1の観点から(つまり、シングルスレッドプログラムの場合)、値を読み取らないため、_x=5;y=6;_は_y=6;x=5;_と一貫していることに同意します。次の行のステートメントは、T1で、実行された順序に関係なく、これらの2つのアクションを表示することが保証されています。

55
assylias