我在Play for Scala中有以下类注释为Singleton。该类的目标是获取/关闭OLAP连接。问题:如何处理多个用户同时访问单例的事实?在Java中,我使用synchronized
,但是Scala呢?
@Singleton
class OlapConnectionPool () {
def getConnection = {
val dataSource = new SimpleOlapDataSource
val config = new GenericObjectPool.Config
//... some connection code
new PooledOlapDataSource(dataSource, config)
}
def close (pods: PooledOlapDataSource) = pods.close
}
答案 0 :(得分:1)
让我们首先解决您的代码段中的潜在问题 - 每次调用getConnection
时都会创建一个新的连接池。这表示资源泄漏,因为很可能单个连接池就足够了。我建议使用以下重构:
@Singleton
class OlapConnectionPool () {
private val ds = {
val dataSource = new SimpleOlapDataSource
val config = new GenericObjectPool.Config
//... some connection code
new PooledOlapDataSource(dataSource, config)
}
def getConnection() = ds.getConnection()
def close() = ds.close()
}
此处ds
仅在单例构造时初始化一次,因此在单例的生命周期内有一个连接池。
Singletons是线程安全的,因为它们不公开暴露共享状态,例如,通过公共var
成员,并且单例的所有依赖关系也是线程安全的。因此,我们需要确定依赖项PooledOlapDataSource
是否是线程安全的。我猜PooledOlapDataSource
来自pivot4j
,因此检查PooledOlapDataSource
源代码我们可以看到它取决于PoolableObjectFactory
,根据docs,它是线程安全的:
PoolableObjectFactory必须是线程安全的。
此外,如果我们检查PoolableObjectFactory.getConnection
的依赖关系,我们会在borrowObject
调用,我们会看到一堆synchronized
。我们可以安全地断定你的单例是线程安全的。
另外,请查看作者建议的this有趣答案:
一般情况下,除非你有,否则最好不要使用@Singleton 公平地理解不变性和线程安全性。