Является ли оператор-оператор атомарным?
В документации говорится, что вы можете использовать if-else
несколько раз или switch-case
:
int condition;
setCondition(int condition) {
this.condition = condition;
}
Либо коммутационный футляр
switch (condition) {
case 1: print("one"); break;
case 2: print("two"); break;
или
if (condition == 1) { print("one"); }
else if (condition == 2) { print("two"); }
Далее, condition
объявлен volatile
, а метод setCondition()
вызывается из нескольких потоков.
if-else
не является атомарным, а volatile
переменная write является синхронизирующим действием. Таким образом, в последнем коде могут быть напечатаны как "одна", так и "две" строки.
Этого можно избежать, если была использована локальная переменная метода с начальным значением:
int localCondition = condition;
if (local condition == ..) ..
Оператор switch-case
содержит некоторую начальную копию переменной? Как выполняются операции с поперечными потоками?
Ответы
Ответ 1
Из спецификация Java в операторах switch:
Когда выполняется оператор switch, сначала вычисляется выражение. [...]
Это говорит о том, что выражение оценивается один раз и что результат временно сохраняется где-то в другом месте, поэтому условия гонки не возможны.
Я не могу найти определенный ответ нигде.
Быстрый тест показывает, что это действительно так:
public class Main {
private static int i = 0;
public static void main(String[] args) {
switch(sideEffect()) {
case 0:
System.out.println("0");
break;
case 1:
System.out.println("1");
break;
default:
System.out.println("something else");
}
System.out.println(i); //this prints 1
}
private static int sideEffect() {
return i++;
}
}
И действительно, sideEffect() вызывается только один раз.
Ответ 2
Выражение оценивается один раз при входе в коммутатор.
Коммутатор может использовать результат внутренне столько раз, сколько нужно, чтобы определить, к какому коду перейти. Это сродни:
int switchValue = <some expression>;
if (switchValue == <some case>)
<do something>
else if (switchValue == <some other case>
<do something else>
// etc
Собственно, коммутатор компилируется в различные стили байтового кода в зависимости от количества случаев и типа значения.
Переключателю нужно только один раз оценить выражение.