在 Scala 中,AnyRef 上有一个同步方法,可让您同步任何扩展 AnyRef 的对象。但是,它在 AnyRef 上是抽象的,我无法从 grepping 源代码中弄清楚它是如何工作的。似乎它是通过利用 Java 中的 synchronized 关键字来工作的。是这样吗?
2 回答
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)。
只是为了补充 Eugene 的答案,他对编译器了如指掌,这里有一个小的 scala 控制台会话。
底线:生成的代码与您在 java 中获得的代码完全相同。没有为同步 { ... } 生成闭包,甚至没有方法调用。只是一个 try/catch,在 try 开始时有一个 monitorenter 字节码 (3),并且在正常出口 (9) 和 catch 出口 (12) 中都有一个 monitorexit。因此,在 scala 中使用 synchronized 与在 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