Scala final 与 val 的并发可见性 [英] Scala final vs val for concurrency visibility

查看:20
本文介绍了Scala final 与 val 的并发可见性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Java 中,当跨多个线程(以及一般情况下)使用一个对象时,最好将字段设为 final.例如,

In Java, when using an object across multiple threads (and in general), it is good practice to make fields final. For example,

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

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

In this case, the visibility of obj will be consistent across multiple threads (let's assume obj has all final fields as well) since it is safely constructed using the final keyword.

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

In scala, it doesn't appear val compiles down to a final reference, but rather val is semantics in scala that prevents you from reassigning a variable (Scala final variables in constructor). If scala constructor variables are not defined as final, will they suffer from the same problem (when using these objects in actors)?

推荐答案

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

The answer to the other question is misleading. There are two meanings of the term final: a) for Scala fields/methods and Java methods it means "cannot be overridden in a subclass" and b) for Java fields and in JVM bytecode it means "the field must be initialized in the constructor and cannot be reassigned".

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

Class parameters marked with val (or, equivalently, case class parameters without a modifier) are indeed final in second sense, and hence thread safe.

这是证明:

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 运行:

Or with javap, which can be conveniently run from the 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 final 与 val 的并发可见性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆