object Users {
val userCountByAgeMap = readFromFile(); // read from file returns immutable map
}与上面的scala示例一样,用户将是Singleton对象,userCountByAgeMap将延迟初始化。
那么这个初始化是原子的吗?也就是说,只有一个线程能够初始化它。
假设userCountByAgeMap由线程A初始化,它对线程B是可见的吗?
如果初始化没有确保原子/内存的可见性,那么将userCountByAgeMap变量作为惰性val来修复吗?
发布于 2017-10-11 04:13:01
在Scala中,对象是在静态块中初始化的,因此JVM保证线程安全(Java静态初始化器是线程安全的)。您可以使用JAD反编译器来分析字节码。以下是代码:
object Users {
val userCountByAgeMap = Map.empty[String, Int]
}并解压缩Users$.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$();
}
}因为您使用的是不可变的Map,它会自动为您提供线程安全。所以可以从不同的线程访问这个字段。
发布于 2017-10-11 05:34:53
是的,val在object中是线程安全的,您不需要将它更改为用于thread safe的lazy val。作为@Artavazd巴拉扬字节码,Scala object等于Java的单例对象,因此它等于:
class Users {
public static Users users;
static {
users = new Users();
}
val userCountByAgeMap = readFromFile(); // read from file returns immutable map
}正如我们所知,Java的静态块将在加载class(用户)时插入,因此它是线程安全的。
需要调用的是,lazy val线程安全用于解决字段--是惰性的,并且只有在它调用时才能执行。但仍然保持它是线程安全的多个线程之间的时,由二次检查锁定插入。
http://docs.scala-lang.org/sips/pending/improved-lazy-val-initialization.html
https://stackoverflow.com/questions/46678886
复制相似问题