Continuing the discussion from [SOLVED] Using `Future` combined with `synchronized`:
Is lazy
thread-safe? Can anyone clarify this?
Continuing the discussion from [SOLVED] Using `Future` combined with `synchronized`:
Is lazy
thread-safe? Can anyone clarify this?
Yes, it is.
class Foo {
lazy val f = 3
}
Looking at the byte code with:
$ scalac foo.scala
$ javap -private -cp . -c Foo
reveals this:
public class Foo {
private int f;
private volatile boolean bitmap$0;
private int f$lzycompute();
Code:
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: aload_0
5: getfield #16 // Field bitmap$0:Z
8: ifne 21
11: aload_0
12: iconst_3
13: putfield #18 // Field f:I
16: aload_0
17: iconst_1
18: putfield #16 // Field bitmap$0:Z
21: aload_1
22: monitorexit
23: goto 29
26: aload_1
27: monitorexit
28: athrow
29: aload_0
30: getfield #18 // Field f:I
33: ireturn
Exception table:
from to target type
4 21 26 any
public int f();
Code:
0: aload_0
1: getfield #16 // Field bitmap$0:Z
4: ifne 14
7: aload_0
8: invokespecial #24 // Method f$lzycompute:()I
11: goto 18
14: aload_0
15: getfield #18 // Field f:I
18: ireturn
public Foo();
Code:
0: aload_0
1: invokespecial #28 // Method java/lang/Object."<init>":()V
4: return
}
As you can see, the private function responsible for computing the value for the lazy val foo
is called f$lzycompute
.
This function uses monitorenter / monitorexit byte code sequences to protect re-computing and setting the value of the field f
.
I’d have taken thread safety of lazy values for granted - interestingly, I can’t find it in the lang spec. Am I missing something?
There seem to be some loose ends in this area (resolved in Scala 3).
Cats Eval.later is an alternative to lazy val and the docs explain why the Cats team provided an alternative. Cats: Eval
lazy vals in scala2.12 and 2.13 are threadsafe. In scala3 you will need to annotate them with @volatile
.
That was true for a while in some earlier Dotty versions, but in the current Scala 3 prereleases, the default behavior is the same as Scala 2’s, as per Make lazy vals thread-safe by default by smarter · Pull Request #6579 · lampepfl/dotty · GitHub
Unlike Scala 2, Scala 3 allows you to opt-out of thread safety with a new @threadUnsafe
annotation.
Oh, good – I’d missed that detail, but I think that’s a better approach. Thanks for the update…