Scala final vs val用于并发可见性

Jef*_*rey 28 concurrency visibility scala final actor

在Java中,当跨多个线程(通常)使用对象时,最好将字段设为final.例如,

public class ShareMe {
    private final MyObject obj;
    public ShareMe(MyObject obj) {
        this.obj = obj;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,obj的可见性将在多个线程中保持一致(假设obj具有所有最终字段),因为它是使用final关键字安全构造的.

在scala中,它不会出现val编译到最终引用,而是val是scala中的语义,阻止您重新分配变量(构造函数中的Scala最终变量).如果scala构造函数变量未定义为final,它们是否会遇到同样的问题(在actor中使用这些对象时)?

ret*_*nym 50

另一个问题的答案是误导性的.这个术语有两个含义final:a)对于Scala字段/方法和Java方法,它意味着"不能在子类中重写"和b)对于Java字段和JVM字节码,它意味着"字段必须在构造函数中初始化,并且不能重新分配".

标有val(或等效地,没有修饰符的case类参数)的类参数在第二种意义上确实是最终的,因此是线程安全的.

这是证据:

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
Run Code Online (Sandbox Code Playgroud)

或者javap,可以从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);
}
Run Code Online (Sandbox Code Playgroud)