在Scala中以线程安全的方式初始化单例元素的正确方法是什么? [英] What is the proper way to initialize singleton element in a thread safe way in Scala?

查看:100
本文介绍了在Scala中以线程安全的方式初始化单例元素的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了在Scala中以线程安全的方式初始化单例元素的问题.通常使用伴随对象.但是这一次我需要将配置对象传递给初始化程序.调用伴侣对象的一些init函数要么不是线程安全的,要么导致锁,这对于Scala来说似乎有点低级(也许我不对).

I've faced a problem of initializing singleton element in a thread safe way in Scala. Usually companion object is used. But this time I need to pass a config object to initializer. Calling some init function of companion object either not thread safe, or leads to locks, that looks kind of low level for Scala (may be I'm not right).

我想到的是一个缓存.使用相同的参数调用cache有助于将其初始化一次.但是对我来说奇怪的是,我必须使用需要更多功能的结构.似乎知道缓存仅存储一个元素可能会导致更好的性能(至少我们不需要每次都计算参数的哈希值). 那么,Scala中是否有这样的单例仅支持一次初始化,而忽略了进一步调用的参数?

The thing I came up with is a cache. Calling cache with the same argument helps to initialize it exactly once. But the strange thing for me is that I have to use structure with much broader functionality that I need. Seems like knowing that cache will store only one element may result in better performance (at least we don't need to calculate hash of argument every time). So is there such a singleton in Scala that supports only one initialization and ignoring argument for further calls?

[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")
}

还是其他解决问题的方法?

Or may be some other approach solving the problem?

推荐答案

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

Well, conceptually it seems weird that several threads are calling initialization with the same (I hope) config. It would be more elegant to initialize your singleton before spawning the threads.

如果由于某种原因而无法执行,则必须同步初始化.这并不是对于Scala而言太底层",这是并发访问变量所需要做的.

If for any reason that's not possible, you have to synchronize the initialization. This is not "too low-level for Scala", it is what need to be done for concurrent access to a variable.

您可以使用def apply(config: <some type>)方法创建一个伴随对象,该方法可以解决此问题并存储单个私有val.如果尚未设置,单独的def apply()可以访问初始化的变量或引发异常.最后一个不需要同步,因为您将只读取该值.小心,尽管出于任何原因您的班级都是可变的.

You can create a companion object with an def apply(config: <some type>) method that takes care of this and stores a single, private val. A separate def apply() can access the initialized variable or thrown an exception if not yet set up. This last one will not need synchronization since you will only be reading the value. Careful though if for whatever reason your class is mutable.

这篇关于在Scala中以线程安全的方式初始化单例元素的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆