Подтвердить что ты не робот

Возвращаемое значение оператора присваивания в параллельном коде

Учитывая следующий класс:

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() и method2() одновременно на одном и том же экземпляре Foo, может ли вызов метода1() когда-либо возвращать что-либо, кроме 1?

4b9b3361

Ответ 1

В JLS 15.26 указано:

Существует 12 операторов присваивания; все они синтаксически правые ассоциативные (они группируются справа налево). Таким образом, a = b = c означает a = (b = c), который присваивает значение c в b и затем присваивает значение b a.

Ответ Ted Hopp показывает, что Sun javac не следует этому поведению, возможно, как оптимизация.

Из-за потока здесь поведение метода 1 будет undefined. Если компилятор Sun делает поведение постоянным, он не нарушает поведение undefined.

Ответ 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, поскольку 1, а не number назначается.

Ответ 3

Либо оператор содержит волатильное чтение, либо не содержит изменчивое чтение. Здесь не может быть никакой двусмысленности, поскольку волатильное чтение очень важно для программирования семантики.

Если 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