Как реализован синхронизированный метод AnyRef?

В Scala существует синхронизированный метод AnyRef, который позволяет синхронизировать любой объект, который расширяет AnyRef. Тем не менее, он абстрактный на AnyRef, и я не мог понять, как это работает с grepping источника scala. Кажется, он работает, используя ключевое слово synchronized в Java. Это тот случай?

Ответ 1

1) AnyRef.synchronized - магический метод, который не существует в исходном коде, но вводится в таблицу символов компилятора при каждом запуске компилятора: Definitions.scala. Например, существует несколько магических методов и классов (Definitions.scala).

2) Если метод завернут в this.synchronized, обертка будет удалена, и метод будет внутренне аннотирован с флагом SYNCHRONIZED (UnCurry.scala), который затем отображается на JVM-флаг доступа ACC_SYNCHRONIZED (GenASM.scala).

3) Другие вызовы SYNCHRONIZED отображаются на базовый примитив SYNCHRONIZED (backend/ScalaPrimitives.scala), который затем опущен в monitorenter/monitorexit (GenICode.scala # 1, GenICode.scala # 2).

Ответ 2

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

В нижней строке: сгенерированный код точно совпадает с тем, что вы получите в java. Для синхронизированного {...} и даже вызова метода нет никакого замыкания. Просто попробуйте/поймайте, где в начале попытки есть байт-код монитора (3), и оба в нормальном выходе (9), а в выводе catch (12) есть monitorexit. Таким образом, нет никаких накладных расходов, связанных с использованием синхронизации в scala vs, используя его в java.

Обратите внимание: большинство людей согласны с тем, что наличие опасных конструкций синхронизации нисходящего потока на каждом объекте обычно считается плохой идеей, которая была выполнена только для совместимости с Java.

scala> class Test { def test { this.synchronized { } } }
defined class Test

scala> :javap -c Test
Compiled from "<console>"
public class Test extends java.lang.Object implements scala.ScalaObject{
public void test();
  Code:
   0:   aload_0
   1:   dup
   2:   astore_1
   3:   monitorenter
   4:   getstatic   #12; //Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit;
   7:   pop
   8:   aload_1
   9:   monitorexit
   10:  return
   11:  aload_1
   12:  monitorexit
   13:  athrow
  Exception table:
   from   to  target type
     4    10    11   any