@xtccc
2016-03-09T10:34:07.000000Z
字数 2262
阅读 2725
Akka
终止Actor有两种方式:
- 对于top-level actor: ActorSystem#stop
- 对于普通的actor及其child actors: ActorContext#stop
终止Actor的过程是异步的,即stop的可能在actor真正终止前就返回了。异步终止的特性会导致: Since stopping an actor is asynchronous, you cannot immediately reuse the name of the child you just stopped; this will result in an InvalidActorNameException. Instead, watch the terminating actor and create its replacement in response to the Terminated message which will eventually arrive.
内部的实现流程:
Termination of an actor proceeds in two steps: first the actor suspends its mailbox processing and sends a stop command to all its children, then it keeps processing the internal termination notifications from its children until the last one is gone, finally terminating itself (invoking postStop, dumping mailbox, publishing Terminated on the DeathWatch, telling its supervisor). If one of the actors does not respond (i.e. processing a message for extended periods of time and therefore not receiving the stop command), this whole process will be stuck.
例
package cn.gridx.scala.akka.tutorial.lifecycle
import akka.actor.{Props, ActorRef, ActorSystem, Actor}
object StopActors {
def main(args: Array[String]): Unit = {
val system = ActorSystem("Stop-Actors-Example")
val actorA = system.actorOf(Props(classOf[ActorA], 5))
Thread.sleep(1000)
actorA ! "Spawn"
Thread.sleep(2000)
actorA ! "Halt"
Thread.sleep(10000)
system.shutdown
}
trait Msg
case class RequestMsg() extends Msg
class ActorA(childrenNum: Int) extends Actor {
val children: Array[ActorRef] = new Array[ActorRef](childrenNum)
def receive = {
case "Spawn" =>
println("[Actor A] 即将创建children actors")
for (i <- 0 until children.size) // 为自己创建若干个child actors
children(i) = context.actorOf(Props(classOf[ActorB], i))
println(s"[Actor A] ${childrenNum}个children actors创建完毕")
case "Halt" =>
children.map(context.stop) // 先把children都终止(这一步实际上是不需要的)
context stop self // 再终止自身
}
override def preStart = {
println("I'm ActorA, I will be started !")
}
override def postStop = {
println("I'm ActorA, I am stopped !")
}
}
class ActorB(n: Int) extends Actor {
def receive = {
case _ => println("[Actor B] 这是啥消息,我也不知道")
}
override def preStart = {
println(s"I'm ActorB-#$n, I will be started !")
}
override def postStop = {
println(s"I'm ActorB-#$n, I am stopped !")
}
}
}
运行输出为:
实际上,如果actorA有若干个children,那么当我们针对actorA调用stop
时,它的child actors会自动地先被终止,因此并不需要对child actors逐个调用stop。
如果要求终止某个actor时,它正在处理消息,怎么办?
该Actor对当前正在处理的消息会继续处理,但是不会处理mailbox中剩下的其他消息。在默认情况下,mailbox中剩余的消息会被发送到ActorSystem的deadLetters(这取决于mailbox的实现)。