在Scala中,AnyRef上有一个synchronized方法,它允许您在任何扩展AnyRef的对象上进行同步。但是,它在AnyRef上是抽象的,我无法弄清楚它是如何通过grepping scala源来实现的。看起来它的工作原理是利用Java中的synchronized关键字。是这样的吗?
答案 0 :(得分:32)
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,{{3 }})。
答案 1 :(得分:9)
只是为了添加Eugene的答案,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