Scala final vs val实现并发可见性

Scala final vs val实现并发可见性,scala,concurrency,visibility,final,actor,Scala,Concurrency,Visibility,Final,Actor,在Java中,当跨多个线程(通常)使用对象时,最好将字段设置为final。比如说, public class ShareMe { private final MyObject obj; public ShareMe(MyObject obj) { this.obj = obj; } } 在这种情况下,obj的可见性将在多个线程中保持一致(假设obj也有所有final字段),因为它是使用final关键字安全构建的 在scala中,似乎val不会编译为最终引

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

public class ShareMe {
    private final MyObject obj;
    public ShareMe(MyObject obj) {
        this.obj = obj;
    }
}
在这种情况下,obj的可见性将在多个线程中保持一致(假设obj也有所有final字段),因为它是使用final关键字安全构建的


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

我想我可能误解了var的编译方式。我创建了示例类

class AVarTest(name:String) {
   def printName() {
     println(name)
   }
}
我运行了
javap-private
,结果是

public class AVarTest extends java.lang.Object implements scala.ScalaObject{
    private final java.lang.String name;
    public void printName();
    public AVarTest(java.lang.String);
}
这个名字实际上是编译成了最终的


另一个问题的答案具有误导性。术语
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
或者使用
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);
}
scala>A类(val A:Any)
定义的A类
scala>:javap-私有A
从“”编译
公共类A扩展了java.lang.Object,实现了scala.ScalaObject{
私有最终java.lang.Object a;
public java.lang.Object a();
公共A(java.lang.Object);
}

感谢您的澄清。你能看到我对这个问题的更新吗?我还看到,对于一个没有修饰符的非case类,构造函数变量被声明为final(如javap所示)。@retronym,我找到你的答案是为了找到我问题的答案。正如您所知,Java中的
final
关键字也用于避免重新定位ctor的指令,如链接中所述。因此,如果我正确理解了您的答案,在Scala类中使用
val
字段等于在Java类中声明
final
字段,让JMM正常工作?请注意,从2.9.0.1(可能更早)开始,您使用字段名的唯一原因是因为您在printName中引用了它。如果没有方法引用ctor参数,它将不再生成字段。