玩Scala和线程安全

Mar*_*rta 5 multithreading scala playframework

该项目使用Play frameworkScala语言编写.我已经实施了compile time dependency.我在Play中关注了这个例子:

https://github.com/playframework/play-scala-compile-di-example

看着MyApplicationLoader.scala:

import play.api._
import play.api.routing.Router

class MyApplicationLoader extends ApplicationLoader {
  private var components: MyComponents = _

  def load(context: ApplicationLoader.Context): Application = {
    components = new MyComponents(context)
    components.application
  }
}

class MyComponents(context: ApplicationLoader.Context) 
  extends BuiltInComponentsFromContext(context)
  with play.filters.HttpFiltersComponents
  with _root_.controllers.AssetsComponents {

  lazy val homeController = new _root_.controllers.HomeController(controllerComponents)

  lazy val router: Router = new _root_.router.Routes(httpErrorHandler, homeController, assets)
}
Run Code Online (Sandbox Code Playgroud)

以及以下代码行:

 lazy val homeController = new _root_.controllers.HomeController(controllerComponents)
Run Code Online (Sandbox Code Playgroud)

我的理解是,HomeController第一次HomeController调用只有一个创建的实例.只要应用程序存在,该实例就会存在.这些陈述是否正确?

HomeController在我的应用程序看起来像这样:

class HomeController{

   val request = // some code here

   val workflowExecutionResult = Workflow.execute(request)

}
Run Code Online (Sandbox Code Playgroud)

所以Workflow是类型object而不是class.

Workflow看起来像这样:

object Workflow {
  def execute(request: Request) = {

    val retrieveCustomersResult = RetrieveCustomers.retrieve() 
    // some code here

    val createRequestResult = CreateRequest.create(request)
    // some code here

    workflowExecutionResult
  }
}
Run Code Online (Sandbox Code Playgroud)

因此,Workflow调用一些域服务,每个域服务都是类型object而不是class.域服务中的所有值都是不可变的,我val到处都在使用.

这足以确保线程安全吗?

我问,因为我习惯于写C# Web APIs一个HomeController看起来像这样的地方:

class HomeControllerInSeeSharpProject{

    // some code here

    var request = new Request() // more code here
    var workflow = new WorkflowInSeeSharpProject()
    var workflowExecutionResult = workflow.execute(request)
}
Run Code Online (Sandbox Code Playgroud)

Workflow看起来像:

public class WorkflowInSeeSharpProject {

  public execute(Request request) {

      var retrieveCustomers = new RetrieveCustomers()
      var retrieveCustomersResult = retrieveCustomers.retrieve()

      // some code here
      var createRequest = new CreateRequest()
      var createRequestResult = createRequest.create(request)

      // some code here
      return workflowExecutionResult
  }
}
Run Code Online (Sandbox Code Playgroud)

因此,在C#项目每次HomeControllerInSeeSharpProject叫的一个新实例WorkflowInSeeSharpProject被创建,所有的域名服务也newed体,然后我可以肯定,国家不能单独的线程之间共享.所以我担心因为我Scala Workflow 和域服务是类型object而不是class可能存在两个请求被发送到HomeController 这两个线程之间共享的情况.

情况可能如此吗?我的应用程序不是线程安全吗?

我已经读过objectScala中的s不是线程安全的,因为它们只有一个实例.但是我也读过,虽然使用vals 不是线程安全的,但是会使应用程序线程安全...

或者也许Play自己有办法解决这个问题?

Mar*_*lic 1

由于您使用的是编译时依赖项注入,因此您可以控制创建的实例数量,并且在您的情况下HomeController仅创建一次。当请求进来时,这个单个实例将在线程之间共享,因此您实际上必须确保它是线程安全的。will的所有依赖项HomeController也需要是线程安全的,因此object Workflow必须是线程安全的。目前,Workflow没有公开公开任何共享状态,因此它是线程安全的。一般来说,val其中的定义object线程安全的

实际上HomeController,行为就像单身人士一样,避免单身人士可能会更安全。例如,默认情况下,Play Framework 使用Guice依赖注入,只要它不是@Singleton. 动机之一是,正如Nio 的回答所建议的那样,无需担心并发保护的状态:

一般来说,最好不要使用@Singleton,除非您对不变性和线程安全性有充分的了解。如果您认为您有 Singleton 的用例,请确保您正在保护任何共享状态。