让Akka演员在不挂其他演员的情况下等待外部输入

时间:2016-04-29 17:35:48

标签: java akka deadlock

Akka( Java API )。假设我有两个演员,WatchdogBlockingListener。他们都注入了彼此的参考:

// WARNING!
// All code here is just Groovy-pseudocode
class Watchdog extends UntypedActor {
    ActorRef blockingListener

    @Override
    void onReceive(Object message) {
        if(message in Init) {
            blockingListener.tell(new StartListening(), self())
        } else if(message in SomethingHappened) {
            ...
        }
    }
}

class BlockingListener extends UntypedActor {
    ActorRef watchdog

    @Override
    void onReceive(Object message) {
        if(message in StartListening) {
            while(true) {
                // Block and scan for input
                String event = waitForNextEvent()

                watchdog.tell(new SomethingHappened(event), self())
            }
        }
    }
}

我担心while(true)中的BlockingListener循环会阻止两个参与者之间的正确沟通。 会吗?我担心当BlockingListener被告知StartListening时,它会:

  1. 输入while(true)循环;然后
  2. 使BlockingListener线程挂起/等待,直到发生一个事件(在actor系统之外);然后
  3. 尝试告诉Watchdog SomethingHappened(event),但......
  4. Watchdog永远不会收到SomethingHappened,因为它仍在等待自己的Init消息完成处理
  5. 我是对的吗?如果是这样,这里有什么补救措施?我们如何让BlockingListener监听演员系统之外的事件并回应它们?

1 个答案:

答案 0 :(得分:1)

ActorSystem包含默认调度程序,它本质上是一个线程池,您可以配置自己的独立调度程序,但如果没有,则使用默认调度程序。

当有人发送WatchDog消息Init时,它将被安排在调度程序的其中一个线程上运行,它会将StartListening消息发送到blockingListener并且然后将线程返回给调度程序(当接收方法完成时)。

然而,当有人发送BlockingListener时,

StartListening将被分配一个线程,它将永远保留,永远不会返回调度员。当它向watchdog发送消息时,如果watchdog将对该消息做出反应,它将取决于可用线程的数量。

一般来说,Akka是围绕不阻挡而设计的,所以你应该尽可能地避免这种情况,但有些情况下可能无法阻止。

在这种情况下你应该做的是将这些actor隔离到一个单独的调度程序上(并且更喜欢基于线程池的调度程序而不是默认的Fork Join Pool),这将确保你的actor消耗一个线程并不是这样的。系统中其他参与者的问题。

然而,还有一个问题,即使你在自己的线程池中隔离了actor,那是因为你的actor被困在while循环中(一个actor只会在同一个线程中执行)它不会对发送停止消息作出反应,甚至不会关闭演员系统 - 演员系统只会挂起。

这可以通过定期断开循环来解决,向actor发送一条消息以继续,然后将其添加到actor邮箱的最后,并允许它处理其他消息并可能停止。这需要waitForNextEvent方法具有某种超时,以便它不会无限期地阻塞。