多个用户在Play for Scala中访问Singleton

时间:2018-06-14 00:06:40

标签: scala playframework

我在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

}

1 个答案:

答案 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   公平地理解不变性和线程安全性。