我是akka的新手。 任何人都可以建议/确认下一个代码/方法在重载下的多线程环境中是否安全? 与Execute方法有关的问题。 也很高兴知道一般/典型的方法。 PS。我确实试过检查下一篇文章:https://twitter.github.io/scala_school/concurrency.html 但这不是Akka特有的等。 谢谢,
以下是代码:
TypeA A001 A002 A003 A004
------- ------------ ------------ ----------- --------------------
AAA001 EXT mail 190.000000 example@example.com
答案 0 :(得分:3)
正如所写,由于ExchangeSystem
的状态是(有效的)全局变量,这对于竞争条件已经成熟。
不是拥有一个带有可变集合的全局对象,而是将一个状态隔离在一个actor中(这是演员的主要目的之一)。
class ExchangeSystem extends Actor {
var openOrders = List.empty[Order]
var executedOrders = List.empty[Order]
def receive = {
case order : Order =>
// Attempt to match order
val matchedOrder = ExchangeSystem.matchOrder( order )
matchedOrder match {
case Some(matched) => execute(matched, order)
case None => openOrders += order
}
}
}
还应将ExchangeSystem.Execute
函数与调用但未在样本中定义的其他函数一起移动到actor中。
您还可以将它们移动到处理业务逻辑的ExchangeSystem类中,并在actor中编写它:
case class ExchangeSystem(openOrders: List[Order], executedOrders: List[Order]) {
def execute(matched: Order, order: Order): ExchangeSystem = {
order.SetAsExecuted(order.price)
matchedOrder.SetAsExecuted(order.price)
this.copy(
openOrders = openOrders - matchedOrder,
executedOrders = executedOrders + order + matchedOrder
)
}
def matchOrder(order: Order): Option[Order] = ???
def withOpenOrder(order: Order): ExchangeSystem = this.copy(openOrders = openOrders + order)
}
注意这个对象是如何不可变的 - 它永远不会修改自己的状态,而是返回一个具有更新状态的新ExchangeSystem
实例。然后你可以将它封装在一个像这样的演员:
class ExchangeSystemActor extends Actor {
var exchangeSystem = ExchangeSystem(Nil, Nil)
def receive = {
case order : Order =>
// Attempt to match order
val matchedOrder = exchangeSystem.matchOrder( order )
matchedOrder match {
case Some(matched) => exchangeSystem = exchangeSystem.execute(matched, order)
case None => exchangeSystem = exchangeSystem.withOpenOrder(order)
}
}
}
现在你已经消除了竞争条件,因为所有操作都是通过传递给actor的消息进行的。您还简化了测试,因为您的业务逻辑可以独立于actor本身进行测试 - 您的测试可以简单地实例化自己的ExchangeSystem
,从而避免强制测试异步的复杂性。
答案 1 :(得分:2)
只是澄清一下。 @Ryan给出了关于通过在Actor中封装状态来降低可见性的好建议,但他的第一个声明是:
由于ExchangeSystem的状态,这对于竞争条件已经成熟 (有效地)全局变量。
给出错误的印象,即竞争条件存在。
实际上,正如所写,根据几个条件,您的代码可能安全,也可能不安全。
如果您只访问Execute
方法并且不直接触摸ListBuffer
,那么您安全,因为此方法已同步。
如果您仅在单 Execute
演员的情况下访问ListBuffer
而未触及ExchangeSystem
字段,则非常安全即使没有明确的同步(实际上,在这种情况下,同步也是不好的做法)。
唯一可能违反线程安全的情况是,如果您尝试直接从不同的线程/ Actors修改ListBuffer
字段,这是可能的,因为它们是公开的(但您还没有证明您是去做)。那是@Ryan的观点。
另请注意,使用Actors时应避免明确同步,请阅读@ Ryan的建议,了解如何更改代码以使其更适合演员。