如果我安全地改变我演员内部的可变地图/队列,我会感到有点困惑。
有人能告诉我这段代码是否是线程安全且正确的?
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是否安全。
答案 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