Scala 中的不变性和线程安全

Immutability and thread-safety in Scala

我正在读 Java concurrency in practice 这本书,当我读到 不变性线程安全 之间的关系时,我试图变得更深。因此,我发现至少有一个用例,其中在 Java 中构造不可变的 class 会导致发布未正确构造的对象。

根据 this link, if the fields of the class are not declated final, the compiler could reorder the statements that needs to be done in order to construct the object. In fact, according to this link,要构建对象,JVM 需要执行这些非原子操作:

  1. 分配一些内存
  2. 创建新对象
  3. 使用默认值初始化它的字段(布尔值为 false,其他基元为 0,对象为 null)
  4. 运行 构造函数,其中也包括 运行ning 父构造函数
  5. 将引用分配给新构造的对象

我的问题是:Scala 怎么样?我知道Scala是基于Java的并发模型,所以也是基于同样的Java内存模型。例如,case class对于上述构造问题是否是线程安全的?

感谢大家。

我在 Whosebug 和 Internet 上进行了一些深入的搜索。关于我提出的问题,没有太多信息。我在 SO 上发现这个问题有一个有趣的答案:Scala final vs val for concurrency visibility.

正如@retronym 所建议的那样,我使用 javap -p A.class 解构了一个包含 case class 并由 scalac 编译的 .class 文件。我发现 class

case class A(val a: Any)

由 scala 编译器编译成相应的 Java class 声明其唯一属性 afinal.

Compiled from "A.scala"
public class A implements scala.Product,scala.Serializable {
  // Final attribute
  private final java.lang.Object a;
  public static <A extends java/lang/Object> scala.Function1<java.lang.Object, A
> andThen(scala.Function1<A, A>);
  public static <A extends java/lang/Object> scala.Function1<A, A> compose(scala
.Function1<A, java.lang.Object>);
  public java.lang.Object a();
  public A copy(java.lang.Object);
  public java.lang.Object copy$default();
  public java.lang.String productPrefix();
  public int productArity();
  public java.lang.Object productElement(int);
  public scala.collection.Iterator<java.lang.Object> productIterator();
  public boolean canEqual(java.lang.Object);
  public int hashCode();
  public java.lang.String toString();
  public boolean equals(java.lang.Object);
  public A(java.lang.Object);
}

正如我们所知,Scala 中的 case class 会自动为我们生成一堆实用程序。还有一个简单的class像这样

class A1(val a: Any)

被翻译成具有 final 属性的 Java class。

总结一下,我想我们可以说只有 val 属性的 Scala class 被翻译成对应的 Java class 有 final 仅限属性。由于JVM的JMM,这个Scalaclass在构建过程中应该线程安全