33

次のクラスがあるとします。

class Foo {
  public volatile int number;

  public int method1() {
    int ret = number = 1;
    return ret;
  }

  public int method2() {
    int ret = number = 2;
    return ret;
  }
}

また、同じインスタンスで同時にmethod1()複数のスレッドを呼び出す場合、method1()を呼び出すと1以外のものが返される可能性がありますか?method2()Foo

4

3 に答える 3

16

答えはコンパイラー次第だと思います。言語は以下を指定します

実行時に、代入式の結果は、代入が発生した後の変数の値になります。

理論的には、2番目(左端)の割り当てが発生する前に値を変更できると思います。

ただし、Sunのjavacコンパイラを使用すると、次のmethod1ようになります。

0:   aload_0
1:   iconst_1
2:   dup_x1
3:   putfield        #2; //Field number:I
6:   istore_1
7:   iload_1
8:   ireturn

これにより、スタック上の定数が複製1され、にロードされてnumberから、retに返されretます。この場合、に格納されている値numberがに割り当てられる前に変更されているかどうかは関係ありません。これは、が割り当てられていないretためです。1number

于 2012-10-12T00:50:19.390 に答える
10

JLS 15.26は、以下を指定します。

12個の代入演算子があります。すべて構文的に右に関連付けられています(右から左にグループ化されます)。したがって、a = b =cはa=(b = c)を意味し、cの値をbに割り当ててから、bの値をaに割り当てます。

Ted Hoppの回答は、Sunのjavacが、おそらく最適化として、この動作に従わないことを示しています。

ここでのスレッド化により、method1の動作は未定義になります。Sunのコンパイラが動作を一定にすると、未定義の動作から外れることはありません。

于 2012-10-12T00:57:58.403 に答える
6

ステートメントに揮発性読み取りが含まれているか、揮発性読み取りが含まれていません。揮発性の読み取りはプログラムのセマンティクスにとって非常に重要であるため、ここではあいまいさはありません。

javacが信頼できる場合、ステートメントには.の揮発性読み取りが含まれていないと結論付けることができますnumber。代入式の値は、実際には(変換後の)x=yの値にすぎません。y

それを推測することもできます

    System.out.println(number=1);

読書を伴わないnumber

    String s;

    (s="hello").length();

読書を伴わないs

    x_1=x_2=...x_n=v

読むことは含まれませんx_n, x_n-1, ...; 代わりに、の値vはに直接割り当てられx_iます(x_n, ... x_i

于 2012-10-12T17:05:56.827 に答える