在scala对象中,是一个不可变的val线程安全吗?

时间:2017-10-11 02:35:59

标签: multithreading scala

object Users {
  val userCountByAgeMap = readFromFile(); // read from file returns immutable map
}

如上例scala中所示,用户将是Singleton对象,而userCountByAgeMap将被懒惰地初始化。

这个初始化是原子的吗?即一个且只有一个线程可以初始化它 假设userCountByAgeMap由线程A初始化,它将对线程B可见。

如果初始化不是原子/内存可见性不确定,那么将userCountByAgeMap变量作为lazy val修复吗?

2 个答案:

答案 0 :(得分:3)

在Scala中,对象在静态块中初始化,因此JVM保证线程安全(Java静态初始化器是线程安全的)。您可以使用JAD decompiler来分析字节码。这是代码:

object Users {
  val userCountByAgeMap = Map.empty[String, Int]
}

反编译用户$ .class文件:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   Users.scala

import scala.Predef$;
import scala.collection.immutable.Map;
import scala.collection.immutable.Map$;

public final class Users$
{

    public Map userCountByAgeMap()
    {
        return userCountByAgeMap;
    }

    private Users$()
    {
        userCountByAgeMap = Predef$.MODULE$.Map().empty();
    }

    public static final Users$ MODULE$ = this;
    private final Map userCountByAgeMap;

    static 
    {
        new Users$();
    }
}

当您使用不可变映射时,它会自动为您提供线程安全性。所以从不同的线程访问这个字段是可以的。

答案 1 :(得分:1)

是的,val object是线程安全的,lazy val您无需将其更改为thread safe。作为@Artavazd Balayan字节码, Scala object等于 Java 的单例对象。所以它等于:

class Users {
    public static Users users;
    static {
      users = new Users();
    }
    val userCountByAgeMap = readFromFile(); // read from file returns immutable map
}

我们知道 Java static block将在加载class(用户)时初始化,因此它是线程安全的。

需要调用,lazy val线程安全用于解决字段是懒惰的,并且只有在调用时才是init。但是当Double checking locking初始化时,仍然在多个线程之间保持线程安全

http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html