Scala final vs val dla widoczności współbieżności

W Javie, gdy używa się obiektu w wielu wątkach (i ogólnie), dobrą praktyką jest, aby pola były ostateczne. Na przykład,

public class ShareMe {
    private final MyObject obj;
    public ShareMe(MyObject obj) {
        this.obj = obj;
    }
}

W tym przypadku widoczność obj będzie spójna w wielu wątkach (Załóżmy, że obj ma również wszystkie końcowe pola), ponieważ jest bezpiecznie skonstruowana przy użyciu ostatecznego słowa kluczowego.

W Scali nie wydaje się, że val kompiluje się do ostatecznego odniesienia, ale raczej val jest semantyką w Scali, która uniemożliwia ponowne przypisanie zmienna (zmienne końcowe Scala w konstruktorze ). Jeśli zmienne konstruktora scala nie są definiowane jako ostateczne, czy będą one cierpieć z tego samego problemu (podczas używania tych obiektów w aktorach)?

Author: Community, 2011-10-02

2 answers

Odpowiedź na inne pytanie jest myląca. Istnieją dwa znaczenia terminu final: a) dla pól/metod Scala i metod Javy oznacza to "nie można nadpisać w podklasie" oraz b) Dla pól Javy i w JVM bytecode oznacza "pole musi być zainicjalizowane w konstruktorze i nie może być ponownie przypisane".

Parametry klasy oznaczone val (lub, równoważnie, parametry klasy case bez modyfikatora) są rzeczywiście ostateczne w drugim sensie, a zatem bezpieczne dla wątku.

Oto dowód:

scala>  class A(val a: Any); class B(final val b: Any); class C(var c: Any)
defined class A
defined class B
defined class C

scala> import java.lang.reflect._
import java.lang.reflect._

scala> def isFinal(cls: Class[_], fieldName: String) = {
     |   val f = cls.getDeclaredFields.find(_.getName == fieldName).get
     |   val mods = f.getModifiers
     |   Modifier.isFinal(mods)
     | }
isFinal: (cls: Class[_], fieldName: String)Boolean

scala> isFinal(classOf[A], "a")
res32: Boolean = true

scala> isFinal(classOf[B], "b")
res33: Boolean = true

scala> isFinal(classOf[C], "c")
res34: Boolean = false

Lub z javap, które można wygodnie uruchomić z REPL:

scala> class A(val a: Any)
defined class A

scala> :javap -private A
Compiled from "<console>"
public class A extends java.lang.Object implements scala.ScalaObject{
    private final java.lang.Object a;
    public java.lang.Object a();
    public A(java.lang.Object);
}
 47
Author: retronym,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-02 18:21:03

Chyba źle zrozumiałem sposób kompilacji var. Stworzyłem przykładową klasę

class AVarTest(name:String) {
   def printName() {
     println(name)
   }
}

Uciekłem javap -private i to spowodowało

public class AVarTest extends java.lang.Object implements scala.ScalaObject{
    private final java.lang.String name;
    public void printName();
    public AVarTest(java.lang.String);
}

I nazwa jest faktycznie skompilowana do finału.

Jest to również pokazane w Scala val musi być strzeżona z synchronizacją dla współbieżnego dostępu?

 1
Author: Jeff Storey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:31