本の中でJava並行性実際には、コンパイラー、実行時のJVM、またはプロセッサーによってプログラムの命令を並べ替えることができると何度か言われています。実行されたプログラムは、ソースコードで指定した順序とまったく同じ順序で命令が実行されないことを前提としています。
ただし、Javaメモリモデルについての最後の章では、JVMが保持する命令の順序を示すhappens-beforeルールのリストを提供します。これらのルールの最初のルールは次のとおりです。
「プログラムの順序」とはソースコードを指していると思います。
私の質問:このルールを前提として、どの命令が実際に並べ替えられるのかと思います。
「アクション」は次のように定義されます。
Javaメモリモデルは、変数の読み取りと書き込み、モニターのロックとロック解除、スレッドの開始と結合などのアクションに関して指定されます。JMMは、発生する前に発生する部分的な順序付けを定義しますプログラム内のすべてのアクションで実行されます。アクションBを実行するスレッドがアクションAの結果を確実に表示できるようにするには(AとBが異なるスレッドで発生するかどうか)、AとBの関係の前に発生する必要があります。 2つの操作間で注文する前に発生する場合、JVMは自由にそれらを自由に再注文できます。
言及されている他の注文ルールは次のとおりです。
プログラムの順序ルールの要点は、スレッド内です。
この単純なプログラムを想像してみてください(最初はすべての変数が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または何も印刷しません。
[〜#〜]編集[〜#〜]
プログラムの順序の意味を誤解しているようです。 プログラムの順序ルールは次のように要約されます :
x
とy
が同じスレッドのアクションであり、x
がプログラムの順序でy
の前にある場合、hb(x, y)
(つまりx
happens-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つのアクションを表示することが保証されています。