Akka Actors - 锁定单一资源请求

时间:2012-11-26 09:56:22

标签: java scala akka actor

我正在使用几个akka演员来监控我的系统,每个演员负责一个不同的组件。

某些演员操作不应该并行执行。 所以我创建了一个持有锁(LockActor)的actor。 一旦演员想要执行此类操作,他需要向LockActor申请批准,并且在获得批准之前他不能执行操作。

如果我想让代码变得简单,在请求的演员中我需要做类似的事情:

while (LockActor.isLockHold()) {
    // perform the operation
}

这当然打破了演员系统的整体设计......

所以我需要使用使代码有点复杂的消息:

  1. Actor B需要将LockRequestMessage发送给LockActor
  2. LockActor持有保存锁定请求的队列
  3. 如果可以锁定,LockActor会将LockApprovalMessage发送给队列中的第一个actor
  4. 当演员B收到LockApprovalMessage(不一定立即)时,他需要执行发送LockRequestMessage时所需的特定操作(每个演员可以有几个需要锁定的操作)
  5. 所以我的问题是 - 在不破坏演员系统设计但仍保持代码尽可能简单的情况下实现此类事情的最佳方法是什么?

3 个答案:

答案 0 :(得分:6)

为什么不用一个演员才能获得锁定,而不是使用单个演员?这是actor模型中的首选方式。

答案 1 :(得分:4)

我在这里看到两种解决方案。

首先,您可以使用ask pattern

class MyActor extends Actor {

    def receive = {
        case Start: {
            val f = lockActor ? LockRequestMessage
            f onSuccess {
                case LockApprovalMessage => {
                    //todo: do your thing
                }
            }
        }
    }

}

请注意,ask方法将创建另一个接收请求消息并完成未来的actor - 请参阅文档以获取更多详细信息。

如果您不想使用提问模式,您可以很好地使用become-unbecome mechanism,如下所示:

class MyActor extends Actor {
    import context._

    def receive = {
        case Start: {
            lockActor ! LockRequestMessage
            become(waitForApproval)
        }
    }    

    def waitForApproval = {
        case LockApprovalMessage => {
            //todo: do your thing
        }
    }


}

您可以很好地处理同一接收函数中的两条消息,但您必须在某个时刻记录演员所处的状态。成为不受欢迎的机制为您实现了这种清晰的分离。

请注意,如果你使用锁来防止演员改变一些共享资源,Akka为此提供了一些更复杂的机制:

查看文档 - 它可能会显着简化您的实施。

答案 2 :(得分:0)

这是一个想法,我不知道细节,因为我是scala的新手:

  • 创建自定义类ActorExecutor,它是一个类型化的actor,它接受闭包作为消息,并通过调用该闭包来处理该消息。

  • 对于每个锁,创建一个ActorExecutor实例

  • 每当actor想要使用lock hold进行某些操作时,它会向ActorExecutor发送一个表示该锁的闭包。

这样,发送到具体的ActorExecutor实例的所有动作都是按顺序执行的。