Akka( Java API )。假设我有两个演员,Watchdog
和BlockingListener
。他们都注入了彼此的参考:
// 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
时,它会:
while(true)
循环;然后BlockingListener
线程挂起/等待,直到发生一个事件(在actor系统之外);然后Watchdog
SomethingHappened(event)
,,但...... Watchdog
永远不会收到SomethingHappened
,因为它仍在等待自己的Init
消息完成处理我是对的吗?如果是这样,这里有什么补救措施?我们如何让BlockingListener
监听演员系统之外的事件并回应它们?
答案 0 :(得分:1)
ActorSystem
包含默认调度程序,它本质上是一个线程池,您可以配置自己的独立调度程序,但如果没有,则使用默认调度程序。
当有人发送WatchDog
消息Init
时,它将被安排在调度程序的其中一个线程上运行,它会将StartListening
消息发送到blockingListener
并且然后将线程返回给调度程序(当接收方法完成时)。
BlockingListener
时, StartListening
将被分配一个线程,它将永远保留,永远不会返回调度员。当它向watchdog
发送消息时,如果watchdog
将对该消息做出反应,它将取决于可用线程的数量。
一般来说,Akka是围绕不阻挡而设计的,所以你应该尽可能地避免这种情况,但有些情况下可能无法阻止。
在这种情况下你应该做的是将这些actor隔离到一个单独的调度程序上(并且更喜欢基于线程池的调度程序而不是默认的Fork Join Pool),这将确保你的actor消耗一个线程并不是这样的。系统中其他参与者的问题。
然而,还有一个问题,即使你在自己的线程池中隔离了actor,那是因为你的actor被困在while循环中(一个actor只会在同一个线程中执行)它不会对发送停止消息作出反应,甚至不会关闭演员系统 - 演员系统只会挂起。
这可以通过定期断开循环来解决,向actor发送一条消息以继续,然后将其添加到actor邮箱的最后,并允许它处理其他消息并可能停止。这需要waitForNextEvent
方法具有某种超时,以便它不会无限期地阻塞。