当前位置: 首页 > 知识库问答 >
问题:

玩Scala和线程安全

宋鸿云
2023-03-14

该项目是使用Play framework和Scala语言编写的。我已经实现了编译时依赖关系。我在游戏中遵循了以下示例:

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

以及以下代码行:

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

我的理解是,在第一次调用HomeController时,只创建了一个HomeController实例。该实例的寿命与应用程序的寿命一样长。这些说法正确吗?

我的应用程序中的HomeController如下所示:

class HomeController{

   val request = // some code here

   val workflowExecutionResult = Workflow.execute(request)

}

因此,工作流属于对象类型,而不是类。

工作流如下所示:

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

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

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

    workflowExecutionResult
  }
}

因此,工作流调用几个域服务,每个域服务的类型都是对象,而不是类。域服务中的所有值都是不可变的,我在任何地方都使用val。

这是否足以确保Thread安全?

我在问,因为我习惯于编写C#Web API,其中一个家庭控制器应该是这样的:

class HomeControllerInSeeSharpProject{

    // some code here

    var request = new Request() // more code here
    var workflow = new WorkflowInSeeSharpProject()
    var workflowExecutionResult = workflow.execute(request)
}

工作流如下所示:

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
  }
}

因此,在C#项目中,每次调用HomeControlllerInSeeSharpProject时,都会创建Workflow InSeeSharpProject的新实例,并且所有域服务也是更新的,然后我可以确定状态不能在单独的线程之间共享。所以我担心,因为我的ScalaWorkflow和域服务的类型是对象而不是,可能会出现两个请求被发送到HomeController并且状态在这两个线程之间共享的情况。

会是这样吗?我的应用程序不是线程安全的吗?

我读到Scala中的对象不是线程安全的,因为它们只有单个实例。然而,我也读到,虽然它们不是线程安全的,但使用vals将使应用程序线程安全...

或者Play本身有办法解决这个问题?

共有1个答案

盖诚
2023-03-14

因为您使用的是编译时依赖项注入,所以您可以控制创建的实例数,在您的情况下,HomeController只创建一次。当请求传入时,这个实例将在线程之间共享,因此您必须确保它是线程安全的。HomeController的所有依赖项也需要是线程安全的,因此对象工作流必须是线程安全的。目前,工作流未公开公开任何共享状态,因此它是线程安全的。通常,对象中的定义是线程安全的。

实际上,HomeController的行为就像单例,避免单例可能更安全。例如,默认情况下,Play Framework使用Guice依赖注入,只要它不是@Singleton,它就会为每个请求创建一个新的控制器实例。一个动机是,正如Nio的回答所建议的那样,对并发保护的担忧更少:

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

 类似资料:
  • 问题内容: 我经常听到对Swing库中缺乏线程安全性的批评。但是,我不确定自己将在自己的代码中执行的操作会导致问题: 在什么情况下,Swing不是线程安全的事实起作用? 我应该积极避免做什么? 问题答案: 切勿执行长时间运行的任务以响应按钮,事件等,因为这些事件在事件线程上。如果您阻止事件线程,则整个GUI将完全无响应,从而使用户感到非常生气。这就是为什么Swing看起来缓慢又硬朗。 使用线程,执

  • 将Scala的值类与Mockito mock(匹配器)一起使用会导致NullPointerException,请参见以下示例: 结果: 任何提示在这里可以做些什么?

  • 问题内容: 我正在寻找关于线程安全信息和。官方文档(http://docs.python.org/library/urllib2.html和http://docs.python.org/library/httplib.html)缺少有关此主题的任何信息。那里甚至没有提到 线程 一词… 更新 好的,它们不是线程安全的。使它们具有线程安全性需要什么,或者存在使它们具有线程安全性的情况?我问是因为好像

  • 问题内容: 在多个类中,是否是线程安全的? 问题答案: 尽管EntityManager实现本身不是线程安全的,但是Java EE容器注入了一个代理,该代理将所有方法调用委托给与事务绑定的EntityManager。因此,每个事务都使用其自己的EntityManager实例。至少对于事务范围的持久性上下文而言,这是正确的(默认设置)。 如果容器将在每个bean中注入EntityManager的新实例

  • 我的Spring项目中有一个简单的: 并按如下方式使用: 我是否必须注意线程安全并使同步(因为不是线程安全的)?我不确定到底是如何工作的--它是否只创建跨所有线程的单个序列化实例?还是为每个转换创建单独的实例?

  • 我试图理解如果下面是线程安全的,它是由另一个开发人员编写的代码,我已经继承和不再与我们在一起。 我有一个BaseProvider类,它实际上是一个消息缓存,由LinkedBlockingQueue表示。该类将传入的消息存储在队列中。 我有一组读此队列的辅助线程。因此,LinkedBlockingQueue是线程安全的。 正如您所注意到的,每个辅助线程都可以访问所有的提供者,所以当一个辅助线程遍历所