【发布时间】:2013-07-13 04:33:59
【问题描述】:
在 Scala 中,AnyRef 上有一个同步方法,可让您同步任何扩展 AnyRef 的对象。但是,它在 AnyRef 上是抽象的,我无法从 grepping 源代码中弄清楚它是如何工作的。似乎它是通过利用 Java 中的 synchronized 关键字来工作的。是这样吗?
【问题讨论】:
标签: scala concurrency
在 Scala 中,AnyRef 上有一个同步方法,可让您同步任何扩展 AnyRef 的对象。但是,它在 AnyRef 上是抽象的,我无法从 grepping 源代码中弄清楚它是如何工作的。似乎它是通过利用 Java 中的 synchronized 关键字来工作的。是这样吗?
【问题讨论】:
标签: scala concurrency
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 中使用同步与在 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
【讨论】: