Actor模型为编写并发和分布式系统提供了一种更高的抽象级别。它将开发人员从显式地处理锁和线程管理的工作中解脱出来,使编写并发和并行系统更加容易。Actor模型是在1973年Carl Hewitt的论文中提的,但是被Erlang语言采用后才变得流行起来,一个成功案例是爱立信使用Erlang非常成功地创建了高并发的可靠的电信系统。 Akka Actor的API与Scala Actor类似,并且从Erlang中借用了一些语法。 首先来一个例子:

创建Actor

定义一个 Actor 类

要定义自己的Actor类,需要继承 Actor 并实现receive 方法. receive 方法需要定义一系列 case 语句(类型为PartialFunction[Any, Unit]) 来描述你的Actor能够处理哪些消息(使用标准的Scala模式匹配),以及实现对消息如何进行处理的代码。

package com.cmcc.family.test

import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging
import akka.actor.ActorSystem
class ActorOne extends Actor {
val log = Logging(context.system, this)
def receive = {
case “hello” ⇒ log.info(“received test:hello”)
case _ ⇒ log.info(“received unknown message”)
}
}

请注意 Akk Actor receive 消息循环是“穷尽的(exhaustive)”, 这与Erlang和Scala的Actor行为不同。 这意味着你需要提供一个对它所能够接受的所有消息的模式匹配规则,如果你希望处理未知的消息,你需要象上例一样提供一个缺省的case分支。否则会有一个 akka.actor.UnhandledMessage(message, sender, recipient) 被发布到Actor系统(ActorSystem)‘的 事件流(EventStream)中。

使用缺省构造方法创建 Actor

object ActorOne extends App{
val system = ActorSystem(“MySystem”)
val myActor:ActorRef = system.actorOf(Props[ActorOne], name = “actorone”)
myActor ! “hello”
}

对 actorOf 的调用返回一个 实例。 这是一个 Actor 实例的句柄(handle),你可以用它来与实际的 Actor进行交互。 The ActorRef 是不可变量,与它所代表的Actor之间是一对一的关系。 The ActorRef 还是可序列化的(serializable),并且携带网络信息。这意味着你可以将它序列化以后,通过网络进行传送,在远程主机上它仍然代表原结点上的同一个Actor。

创建 子 Actor

在上面的例子中,actor是从系统创建的。也可以从其它的actor使用actor 上下文(context) 来创建. 其中的区别在于监管树是如何组织的。使用上下文时当前的actor将成为所创建的子actor的监管者。而使用系统时创建的actor将成为顶级actor,它由系统(内部监管actor)来监管。

class ActorOneSon extends Actor {
val myActorSon = context.actorOf(Props[ActorOne], name = “actoroneson”)
}

重写preStart 方法

当你创建 Actor 时它会自动调用 Actor trait 的preStart 回调方法。这是一个非常好的用来添加actor初始化代码的位置。

override def preStart{
log.info(this.getClass.getSimpleName+“start~~~”)
//…
//初始化代码
}

使用非缺省构造方法创建 Actor

如果你的Actor的构造方法带参数,那么你不能使用 actorOf(Props[TYPE]) 来创建它。 这时你可以用 actorOf的带有传名调用的块的变体,这样你可以用任意方式来创建actor。

class ActorOneParam(val whosay:String) extends Actor {
val log = Logging(context.system, this)
def receive = {
case “hello” ⇒ log.info(s"received test:${whosay}:hello")
case _ ⇒ log.info(“received unknown message”)
}
}

object ActorMain extends App{
val system = ActorSystem(“MySystem”)
//val myActor:ActorRef = system.actorOf(Props[ActorOne], name = “actorone”)
val myActor = system.actorOf(Props(new ActorOneParam(“jingshuai”)), name = “actoroneparam”)
myActor ! “hello”
}

使用Props创建Actor

Actor可以通过将 Props 实例传入 actorOf 工厂方法来创建。

import akka.actor.Props
val myActor = system.actorOf(Props[MyActor].withDispatcher(“my-dispatcher”), name = “myactor2”)

完整代码

package com.cmcc.family.test

import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging
import akka.actor.ActorSystem
import akka.actor.ActorRef
class ActorOne extends Actor {
val log = Logging(context.system, this)
override def preStart {
log.info(this.getClass.getSimpleName + “start~~~”)
//…
//初始化代码
}
def receive = {
case “hello” ⇒ log.info(“received test:hello”)
case _ ⇒ log.info(“received unknown message”)
}
}
class ActorOneParam(val whosay: String) extends Actor {
val log = Logging(context.system, this)
def receive = {
case “hello” ⇒ log.info(s"received test:${whosay}:hello")
case _ ⇒ log.info(“received unknown message”)
}
}
class ActorOneSon extends Actor {
val myActorSon = context.actorOf(Props[ActorOne], name = “actoroneson”)
def receive = {
case x ⇒ myActorSon ! x
}
}

object ActorMain extends App {
val system = ActorSystem(“MySystem”)
//val myActor:ActorRef = system.actorOf(Props[ActorOne], name = “actorone”)
val myActor = system.actorOf(Props(new ActorOneParam(“jingshuai”)), name = “actoroneparam”)
myActor ! “hello”
}