加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Scala final vs val并发可见性

发布时间:2020-12-16 09:43:19 所属栏目:安全 来源:网络整理
导读:在Java中,当跨多个线程(通常)使用对象时,最好将字段设为final。例如, public class ShareMe { private final MyObject obj; public ShareMe(MyObject obj) { this.obj = obj; }} 在这种情况下,obj的可视性在多个线程之间是一致的(假设obj也有所有final字
在Java中,当跨多个线程(通常)使用对象时,最好将字段设为final。例如,

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

在这种情况下,obj的可视性在多个线程之间是一致的(假设obj也有所有final字段),因为它是使用final关键字安全构造的。

在scala中,它不会显示val编译到最后的引用,而是val是scala中的语义阻止您重新分配变量(Scala final variables in constructor)。如果scala构造函数变量没有被定义为final,那么它们会遇到同样的问题(在actor中使用这些对象时)?

解决方法

另一个问题的答案是误导的。术语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);
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读