Могу ли я иметь локальную переменную в Scala как Volatile, поскольку в Java это невозможно? - PullRequest
0 голосов
/ 30 апреля 2018

Насколько я знаю, поле в Java и Scala, помеченное как Volatile, обеспечивает взаимосвязь "происходит до".

В Java невозможно иметь локальную переменную в методе как volatile. Однако компилятор Scala допускает такие вещи, как в приведенном ниже коде:

def test: Unit = {
  @volatile var doNotStop = true 
}

Действительно ли он работает так же, как в Java? Какова семантика такого кода? Как это выглядит в байт-коде и в JVM во время выполнения?

В Java такая переменная, если она передана замыканию, может быть изменена другим потоком, поэтому обязательно быть конечным, верно?

1 Ответ

0 голосов
/ 01 мая 2018

TL; DR : аннотация @volatile выглядит так, как будто она игнорируется при применении к локальной переменной, за исключением случаев, когда переменная может быть экранирована из этой локальной области внутри замыкания.

Чтобы убедиться в этом, мы можем получить байт-код, соответствующий следующему фрагменту

class Foo {
    def test: Unit = {
      @volatile var doNotStop: Boolean = true 
    }
}

Файл класса, полученный с помощью scalac, можно декомпилировать с помощью javap -c -v -p. Вот соответствующая часть для test метода:

public void test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=1
         0: iconst_1
         1: istore_1
         2: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            1       1     1 doNotStop   Z
      ...

Обратите внимание, что нет информации, касающейся какого-либо энергозависимого доступа.

Если вместо этого мы решим объявить doNotStop в качестве переменной экземпляра, то javap покажет следующее объявление поля с четким изменяемым флагом:

private volatile boolean doNotStop;
  descriptor: Z
  flags: ACC_PRIVATE, ACC_VOLATILE

Однако ваше беспокойство по поводу локальной переменной, выходящей из ее области действия, полностью оправдано! Давайте попробуем это:

class Foo {
    def test = {
        var doNotStop: Boolean = true
        () => doNotStop = false
    }
}

Использование javap -p (на этот раз не нужно смотреть на байт-код или флаги) дает нам следующие определения:

public class Foo {
  public scala.Function0<scala.runtime.BoxedUnit> test();
  public static final void $anonfun$test$1(scala.runtime.BooleanRef);
  public Foo();
  private static java.lang.Object $deserializeLambda$(java.lang.invoke.SerializedLambda);
}

Вы можете видеть, что замыкание было скомпилировано в его собственный метод с именем $anonfun$test$1, который принимает BooleanRef. Это BooleanRef является представлением времени выполнения для doNotStop и включает boolean. Для получения дополнительной информации о последнем объявлении вы можете обратиться к связанной документации Java .

Теперь для раскрытия: что если мы снова сделаем doNotStop волатильным?

public class Foo {
  public scala.Function0<scala.runtime.BoxedUnit> test();
  public static final void $anonfun$test$1(scala.runtime.VolatileBooleanRef);
  public Foo();
  private static java.lang.Object $deserializeLambda$(java.lang.invoke.SerializedLambda);
}

Класс остался в основном таким же, но $anonfun$test$1 теперь занимает VolatileBooleanRef. Угадайте, как реализован его внутренний boolean:

volatile public boolean elem;

Семантика здесь очень ясна: ваша не очень локальная переменная Boolean представляется как поле экземпляра BooleanRef во время выполнения. Именно это поле может быть помечено volatile аннотацией. Вот, пожалуйста, @volatile был там полезен!

Чтобы ответить на ваш второй вопрос: закрытие Java закрывается только над значениями, которые «фактически являются окончательными», что запретило бы этот шаблон, когда значение doNotStop изменяется внутри замыкания. Конечно, вы можете реализовать его так же, как это было сделано здесь, используя «эффективно окончательную» ссылку на (Volatile)BooleanRef, чей elem может быть свободно изменен закрытием.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...