object Users {
val userCountByAgeMap = readFromFile(); // read from file returns immutable map
}
如上例scala中所示,用户将是Singleton对象,而userCountByAgeMap将被懒惰地初始化。
这个初始化是原子的吗?即一个且只有一个线程可以初始化它 假设userCountByAgeMap由线程A初始化,它将对线程B可见。
如果初始化不是原子/内存可见性不确定,那么将userCountByAgeMap变量作为lazy val修复吗?
答案 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