并发代码中赋值运算符的返回值

2022-09-01 09:58:09

给定以下类:

class Foo {
  public volatile int number;

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

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

并且给定多个线程在同一实例上调用并发,对formula1()的调用是否可以返回除1之外的任何内容?method1()method2()Foo


答案 1

我认为答案取决于编译器。语言指定

在运行时,赋值表达式的结果是赋值发生后的变量值。

我认为从理论上讲,在第二个(最左边的)赋值发生之前可以更改该值。

但是,使用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

这会复制堆栈上的常量,并将其加载到 中,然后在返回之前加载到 中。在这种情况下,在赋值 到 之前是否修改了 中存储的值并不重要,因为 分配的 不是。1numberretretnumberret1number


答案 2

JLS 15.26 指定:

有12个赋值运算符;它们在语法上都是右结合的(它们从右到左分组)。因此,a=b=c 表示 a=(b=c),它将 c 的值赋给 b,然后将 b 的值赋给 a。

Ted Hopp的回答表明,Sun的javac并没有遵循这种行为,可能是一种优化。

由于此处的线程化,方法 1 的行为将未定义。如果 Sun 的编译器使行为恒定,那么它就不会与未定义的行为中断。


推荐