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