开关运算符是原子的吗?

在文档中,据说您可以同样多次使用或:if-elseswitch-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"); }

接下来,声明并从多个线程调用方法。 不是原子的,变量写入是同步操作。因此,“一”和“二”字符串都可以打印在最后一个代码中。conditionvolatilesetCondition()If-elsevolatile

如果使用具有初始值的方法局部变量,则可以避免这种情况:

int localCondition = condition;
if (local condition == ..) ..

运算符是否包含变量的某个初始副本?如何使用它实现跨线程操作?switch-case


答案 1

Java 规范 on 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

实际上,开关会根据事例数和值的类型编译为各种字节代码样式。

开关只需计算表达式一次。