In Scala, there's a synchronized method on AnyRef which lets you synchronize on any object that extends AnyRef. However, it's abstract on AnyRef, and I couldn't figure out how it worked from grepping the scala source. It seems like it works by exploiting the synchronized keyword in Java. Is that the case?
1) AnyRef.synchronized
is a magic method that doesn't exist in source code, but is injected into the compiler's symbol table on every startup of the compiler: Definitions.scala. There's a number of magic methods and classes, by the way (Definitions.scala).
2) If a method is wrapped in this.synchronized
, the wrapping is dropped, and the method is internally annotated with a SYNCHRONIZED
flag (UnCurry.scala), which is then mapped to JVM's `ACC_SYNCHRONIZED method access flag (GenASM.scala).
3) Other calls to synchronized
are mapped onto the backend's primitive SYNCHRONIZED
(backend/ScalaPrimitives.scala), which is later lowered into monitorenter/monitorexit (GenICode.scala #1, GenICode.scala #2).
Just to add to the answer from Eugene, who knows the compiler by heart, here is a little scala console session.
The bottom line: the generated code is exactly identical to what you would get in java. There is no closure generated for the synchronized { ... } and not even a method call. Just a try/catch where at the beginning of the try there is a monitorenter bytecode (3) and both in the normal exit (9) an in the catch exit (12) there is a monitorexit. So there is no overhead involved in using synchronized in scala vs using it in java.
Note that most people agree that having dangerous low level thread synchronization constructs on every object is generally considered a bad idea that was only done for java compatibility.
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
© 2022 - 2024 — McMap. All rights reserved.