Akka并发编程——第二节:Actor模型(一)
本節(jié)主要內(nèi)容
1. 定義Actor
通過(guò)擴(kuò)展akka.actor.Actor 特質(zhì)并實(shí)現(xiàn)receive方法來(lái)定義Actor,代碼示例如下
//通過(guò)擴(kuò)展Actor并實(shí)現(xiàn)receive方法來(lái)定義Actor class MyActor extends Actor {//獲取LoggingAdapter,用于日志輸出val log = Logging(context.system, this)//實(shí)現(xiàn)receive方法,定義Actor的行為邏輯,返回的是一個(gè)偏函數(shù)def receive = {case "test" => log.info("received test")case _ => log.info("received unknown message")}}receive方法被定義在Actor當(dāng)中,方法標(biāo)簽如下
//Actor中的receive方法定義, type Receive = PartialFunction[Any, Unit] def receive: Actor.Receive下面給出其完整使用代碼:
object Example_01 extends App{import akka.actor.Actorimport akka.event.Loggingimport akka.actor.ActorSystemimport akka.actor.Propsclass MyActor extends Actor {val log = Logging(context.system, this)def receive = {case "test" => log.info("received test")case _ => log.info("received unknown message")}}//創(chuàng)建ActorSystem對(duì)象val system = ActorSystem("MyActorSystem")//返回ActorSystem的LoggingAdpaterval systemLog=system.log//創(chuàng)建MyActor,指定actor名稱為myactorval myactor = system.actorOf(Props[MyActor], name = "myactor")systemLog.info("準(zhǔn)備向myactor發(fā)送消息")//向myactor發(fā)送消息myactor!"test"myactor! 123//關(guān)閉ActorSystem,停止程序的運(yùn)行system.shutdown() }代碼運(yùn)行結(jié)果:
[INFO] [04/02/2016 09:29:54.223] [main] [ActorSystem(MyActorSystem)] 準(zhǔn)備向myactor發(fā)送消息 [INFO] [04/02/2016 09:29:54.224] [MyActorSystem-akka.actor.default-dispatcher-3] [akka://MyActorSystem/user/myactor] received test [INFO] [04/02/2016 09:29:54.224] [MyActorSystem-akka.actor.default-dispatcher-3] [akka://MyActorSystem/user/myactor] received unknown message輸出“[INFO] [04/02/2016 09:29:54.224] [MyActorSystem-akka.actor.default-dispatcher-3] [akka://MyActorSystem/user/myactor] received test”中的[MyActorSystem-akka.actor.default-dispatcher-3]為對(duì)應(yīng)的線程名,[akka://MyActorSystem/user/myactor]為Actor路徑信息, received test為
def receive = {case "test" => log.info("received test")case _ => log.info("received unknown message")}方法處理后的輸出。關(guān)于[akka://MyActorSystem/user/myactor]路徑信息,將在后續(xù)內(nèi)容中進(jìn)行詳細(xì)闡述。
也可以通過(guò)混入ActorLogging來(lái)實(shí)現(xiàn)日志功能,具體代碼如下:
class MyActor extends Actor with ActorLogging{def receive = {case "test" => log.info("received test")case _ => log.info("received unknown message")}}ActorLogging的定義如下:
trait ActorLogging { this: Actor ?private var _log: LoggingAdapter = _def log: LoggingAdapter = {// only used in Actor, i.e. thread safeif (_log eq null)_log = akka.event.Logging(context.system, this)_log}}完整代碼如下:
/**定義Actor時(shí)混入ActorLogging*/ object Example_02 extends App{import akka.actor.Actorimport akka.actor.ActorSystemimport akka.actor.Propsclass MyActor extends Actor with ActorLogging{def receive = {case "test" => log.info("received test")case _ => log.info("received unknown message")}}//創(chuàng)建ActorSystem對(duì)象val system = ActorSystem("MyActorSystem")//返回ActorSystem的LoggingAdpaterval systemLog=system.log//創(chuàng)建MyActor,指定actor名稱為myactorval myactor = system.actorOf(Props[MyActor], name = "myactor")systemLog.info("準(zhǔn)備向myactor發(fā)送消息")//向myactor發(fā)送消息myactor!"test"myactor! 123//關(guān)閉ActorSystem,停止程序的運(yùn)行system.shutdown() }代碼運(yùn)行結(jié)果:
[INFO] [04/02/2016 09:39:21.088] [main] [ActorSystem(MyActorSystem)] 準(zhǔn)備向myactor發(fā)送消息 [INFO] [04/02/2016 09:39:21.089] [MyActorSystem-akka.actor.default-dispatcher-3] [akka://MyActorSystem/user/myactor] received test [INFO] [04/02/2016 09:39:21.089] [MyActorSystem-akka.actor.default-dispatcher-3] [akka://MyActorSystem/user/myactor] received unknown message代碼原理與Example_01類似,這里不再贅述。
2. 創(chuàng)建Actor
在前面兩個(gè)例子中,通過(guò)
val myactor = system.actorOf(Props[MyActor], name = "myactor")創(chuàng)建Actor,需要注意的是system.actorOf方法返回的是ActorRef對(duì)象,ActorRef為Actor的引用,使用ActorRef對(duì)象可以進(jìn)行消息的發(fā)送等操作。Props為配置對(duì)象,在創(chuàng)建Actor時(shí)使用,它是不可變的對(duì)象,因此它是線程案例且完全可共享的。Akka中創(chuàng)建Actor時(shí),也允許直接傳入MyActor對(duì)象的引用,例如
//直接通過(guò)new MyActor的方式傳入MyActor對(duì)象的引用,注意這里是Props(new MyActor) val myactor = system.actorOf(Props(new MyActor), name = "myactor")但是Akka不推薦這么做,官方文檔給出的解釋是這種方式會(huì)導(dǎo)致不可序列化的Props對(duì)象且可能會(huì)導(dǎo)致競(jìng)爭(zhēng)條件(破壞Actor的封裝性)。另外需要特別注意的是,不允許通過(guò)下列代碼創(chuàng)建Actor
//下列兩行代碼編譯可以通過(guò),但運(yùn)行時(shí)出拋出異常val myActor=new MyActorval myactor = system.actorOf(Props(myActor), name = "myactor")完整運(yùn)行代碼如下:
/**創(chuàng)建Actor*/ object Example_03 extends App{import akka.actor.Actorimport akka.actor.ActorSystemimport akka.actor.Propsclass MyActor extends Actor with ActorLogging{def receive = {case "test" => log.info("received test")case _ => log.info("received unknown message")}}val system = ActorSystem("MyActorSystem")val systemLog=system.log//下列兩行代碼編譯可以通過(guò),但運(yùn)行時(shí)出拋出異常val myActor=new MyActorval myactor = system.actorOf(Props(myActor), name = "myactor")systemLog.info("準(zhǔn)備向myactor發(fā)送消息")//向myactor發(fā)送消息myactor!"test"myactor! 123//關(guān)閉ActorSystem,停止程序的運(yùn)行system.shutdown() }運(yùn)行結(jié)果如下:
Exception in thread "main" akka.actor.ActorInitializationException: You cannot create an instance of [chapter02.Example_03$MyActor] explicitly using the constructor (new). You have to use one of the 'actorOf' factory methods to create a new actor. See the documentation.at akka.actor.ActorInitializationException$.apply(Actor.scala:167)at akka.actor.Actor$class.$init$(Actor.scala:423)at chapter02.Example_03$MyActor.<init>(MyActor.scala:73)at chapter02.Example_03$delayedInit$body.apply(MyActor.scala:84)at scala.Function0$class.apply$mcV$sp(Function0.scala:40)at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)at scala.App$$anonfun$main$1.apply(App.scala:71)at scala.App$$anonfun$main$1.apply(App.scala:71)at scala.collection.immutable.List.foreach(List.scala:318)at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)at scala.App$class.main(App.scala:71)at chapter02.Example_03$.main(MyActor.scala:68)at chapter02.Example_03.main(MyActor.scala)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:606)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)從“You cannot create an instance of [chapter02.Example_03$MyActor] explicitly using the constructor (new). You have to use one of the ‘a(chǎn)ctorOf’ factory methods to create a new actor.”可以看到,不能通過(guò)顯式地調(diào)用構(gòu)造函數(shù)創(chuàng)建Actor,只能使用actorOf工廠方法創(chuàng)建Actor。
下面介紹2種在實(shí)際中經(jīng)常使用的Actor創(chuàng)建方法
(1)調(diào)用system.actorOf創(chuàng)建Actor
完整代碼在Example_01、Example_02中已經(jīng)演示過(guò)了,這里需要說(shuō)明的是通過(guò)system.actorOf工廠方法創(chuàng)建的Actor為頂級(jí)Actor
在Akka框架中,每個(gè)Akka應(yīng)用程序都會(huì)有一個(gè)守衛(wèi)Actor,名稱為user,所有通過(guò)system.actorOf工廠方法創(chuàng)建的Actor都為user的子Actor,也是整個(gè)Akka程序的頂級(jí)Actor。
(2)調(diào)用context.actorOf創(chuàng)建Actor
完整代碼如下:
- 1
代碼運(yùn)行結(jié)果
[INFO] [04/02/2016 15:05:34.770] [main] [ActorSystem(MyActorSystem)] 準(zhǔn)備向myactor發(fā)送消息 [INFO] [04/02/2016 15:05:34.771] [MyActorSystem-akka.actor.default-dispatcher-3] [akka://MyActorSystem/user/firstActor/myChild] received test [INFO] [04/02/2016 15:05:34.771] [MyActorSystem-akka.actor.default-dispatcher-2] [akka://MyActorSystem/user/firstActor] received test [INFO] [04/02/2016 15:05:34.771] [MyActorSystem-akka.actor.default-dispatcher-2] [akka://MyActorSystem/user/firstActor] received 123 [INFO] [04/02/2016 15:05:34.771] [MyActorSystem-akka.actor.default-dispatcher-3] [akka://MyActorSystem/user/firstActor/myChild] received unknown message通過(guò)代碼的運(yùn)行結(jié)果可以看到,FirstActor的Actor路徑信息為akka://MyActorSystem/user/firstActor,而通過(guò)
class FirstActor extends Actor with ActorLogging{//通過(guò)context.actorOf方法創(chuàng)建Actorval child = context.actorOf(Props[MyActor], name = "myChild")def receive = {case x => child ! x;log.info("received "+x)}}代碼使用context.actorOf創(chuàng)建的MyActor,其Actor路徑信息為[akka://MyActorSystem/user/firstActor/myChild],這意味著mychild為firstActor的子Actor,層次結(jié)構(gòu)如下圖所示
也就是說(shuō)context.actorOf和system.actorOf的差別是system.actorOf創(chuàng)建的actor為頂級(jí)Actor,而context.actorOf方法創(chuàng)建的actor為調(diào)用該方法的Actor的子Actor
總結(jié)
以上是生活随笔為你收集整理的Akka并发编程——第二节:Actor模型(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: TensorFlow学习笔记(一)安装、
- 下一篇: Akka并发编程——第三节:Actor模