在Scala中以线程安全方式初始化单例元素的正确方法是什么?

时间:2015-04-06 12:32:17

标签: multithreading scala thread-safety singleton

我遇到了在Scala中以线程安全方式初始化singleton元素的问题。通常使用伴侣对象。但是这次我需要将配置对象传递给初始化器。调用伴随对象的某些init函数要么不是线程安全的,要么导致锁定,这看起来对Scala来说是低级别的(可能我不对)。

我想出的是缓存。使用相同的参数调用缓存有助于将其初始化一次。但对我来说奇怪的是我必须使用具有我需要的更广泛功能的结构。看起来知道缓存只存储一个元素可能会带来更好的性能(至少我们不需要每次都计算参数的哈希值)。 那么Scala中是否有这样的单例只支持一次初始化并忽略进一步调用的参数?

[thread 1]
a = A(config) // initialization is initiated
[thread 2, 3, ..]
a = A(config) // initialized object is used

// only one entity of class should exist
class A(config: Config) {
  // should be done once
  client = config.getString("client")
}

或者可能是解决问题的其他方法?

1 个答案:

答案 0 :(得分:0)

好吧,从概念上讲,几个线程使用相同的(我希望)配置调用初始化似乎很奇怪。在产生线程之前初始化你的单例会更优雅。

如果出于任何原因无法实现,则必须同步初始化。这不是“Scala的级别太低”,需要对并发访问变量进行操作。

您可以使用def apply(config: <some type>)方法创建一个伴随对象来处理此问题并存储单个私有val。单独的def apply()可以访问初始化变量,或者如果尚未设置则抛出异常。最后一个不需要同步,因为您只会读取该值。但是,无论出于何种原因,你的课程都是可变的。