我是否安全地在我的akka​​演员中进行变异,或者这不是线程安全吗?

时间:2017-09-14 02:21:45

标签: scala akka

如果我安全地改变我演员内部的可变地图/队列,我会感到有点困惑。

有人能告诉我这段代码是否是线程安全且正确的?

class SomeActor extends Actor {
  val userQ = mutable.Queue.empty[User]
  val tranQ = mutable.Map.empty[Int, Transaction]

  def receive = {
    case Blank1 =>
      if(userQ.isEmpty) 
        userQ ++= getNewUsers()
    case Blank2 =>
      val companyProfile = for {
         company <- api.getCompany() // Future[Company]
         location <- api.getLoc() // Future[Location]
      } yield CompanyProfile(company, location)

      companyProfile.map { cp => 
        tranQ += cp.id -> cp.transaction   // tranQ mutatated here
      }
  }
}

由于我用期货改变了tranQ,这样安全吗?

据我所知,每个actor消息都是以串行方式处理的,所以虽然可能不赞成我可以使用像这样的可变状态。

我很困惑,如果在未来的电话中使用它,比如tranQ是否安全。

1 个答案:

答案 0 :(得分:7)

不,你的代码不安全。

当一个actor一次处理一条消息时,只要Future被调用,你就会失去这个保证。此时,Future内的代码在(可能)不同的线程上执行,下一条消息可能由actor处理。

解决此问题的典型模式是使用Future模式发送包含pipeTo结果的邮件,如下所示:

import akka.pattern.pipe

def receive: Receive {
  case MyMsg =>
    myFutureOperation()
     .map(res => MyMsg2(res))
     .pipeTo(self)
  case MyMsg2(res) =>
    // do mutation now
}

有关使用Future的更多信息,请参阅akka的文档:http://doc.akka.io/docs/akka/2.5/scala/futures.html