本节主要内容

  1. 定义Actor
  2. 创建Actor

1. 定义Actor

通过扩展akka.actor.Actor 特质并实现receive方法来定义Actor,代码示例如下

//通过扩展Actor并实现receive方法来定义Actor
class MyActor extends Actor {//获取LoggingAdapter,用于日志输出val log = Logging(context.system, this)//实现receive方法,定义Actor的行为逻辑,返回的是一个偏函数def receive = {case "test" => log.info("received test")case _      => log.info("received unknown message")}}

receive方法被定义在Actor当中,方法标签如下

//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")}}//创建ActorSystem对象val system = ActorSystem("MyActorSystem")//返回ActorSystem的LoggingAdpaterval systemLog=system.log//创建MyActor,指定actor名称为myactorval myactor = system.actorOf(Props[MyActor], name = "myactor")systemLog.info("准备向myactor发送消息")//向myactor发送消息myactor!"test"myactor! 123//关闭ActorSystem,停止程序的运行system.shutdown()
}

代码运行结果:

[INFO] [04/02/2016 09:29:54.223] [main] [ActorSystem(MyActorSystem)] 准备向myactor发送消息
[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]为对应的线程名,[akka://MyActorSystem/user/myactor]为Actor路径信息, received test为

def receive = {case "test" => log.info("received test")case _      => log.info("received unknown message")}

方法处理后的输出。关于[akka://MyActorSystem/user/myactor]路径信息,将在后续内容中进行详细阐述。


也可以通过混入ActorLogging来实现日志功能,具体代码如下:

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时混入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")}}//创建ActorSystem对象val system = ActorSystem("MyActorSystem")//返回ActorSystem的LoggingAdpaterval systemLog=system.log//创建MyActor,指定actor名称为myactorval myactor = system.actorOf(Props[MyActor], name = "myactor")systemLog.info("准备向myactor发送消息")//向myactor发送消息myactor!"test"myactor! 123//关闭ActorSystem,停止程序的运行system.shutdown()
}

代码运行结果:

[INFO] [04/02/2016 09:39:21.088] [main] [ActorSystem(MyActorSystem)] 准备向myactor发送消息
[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. 创建Actor

在前面两个例子中,通过

 val myactor = system.actorOf(Props[MyActor], name = "myactor")

创建Actor,需要注意的是system.actorOf方法返回的是ActorRef对象,ActorRef为Actor的引用,使用ActorRef对象可以进行消息的发送等操作。Props为配置对象,在创建Actor时使用,它是不可变的对象,因此它是线程案例且完全可共享的。Akka中创建Actor时,也允许直接传入MyActor对象的引用,例如

//直接通过new MyActor的方式传入MyActor对象的引用,注意这里是Props(new MyActor)
val myactor = system.actorOf(Props(new MyActor), name = "myactor")

但是Akka不推荐这么做,官方文档给出的解释是这种方式会导致不可序列化的Props对象且可能会导致竞争条件(破坏Actor的封装性)。另外需要特别注意的是,不允许通过下列代码创建Actor

//下列两行代码编译可以通过,但运行时出抛出异常val  myActor=new MyActorval myactor = system.actorOf(Props(myActor), name = "myactor")

完整运行代码如下:

/**创建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//下列两行代码编译可以通过,但运行时出抛出异常val  myActor=new MyActorval myactor = system.actorOf(Props(myActor), name = "myactor")systemLog.info("准备向myactor发送消息")//向myactor发送消息myactor!"test"myactor! 123//关闭ActorSystem,停止程序的运行system.shutdown()
}

运行结果如下:

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 ‘actorOf’ factory methods to create a new actor.”可以看到,不能通过显式地调用构造函数创建Actor,只能使用actorOf工厂方法创建Actor。

下面介绍2种在实际中经常使用的Actor创建方法
(1)调用system.actorOf创建Actor

val system = ActorSystem("mySystem")
val myActor = system.actorOf(Props[MyActor], "myactor2")

完整代码在Example_01、Example_02中已经演示过了,这里需要说明的是通过system.actorOf工厂方法创建的Actor为顶级Actor

在Akka框架中,每个Akka应用程序都会有一个守卫Actor,名称为user,所有通过system.actorOf工厂方法创建的Actor都为user的子Actor,也是整个Akka程序的顶级Actor。

(2)调用context.actorOf创建Actor
完整代码如下:

/**创建Actor,调用context.actorOf方法*/
object Example_04 extends App{import akka.actor.Actorimport akka.actor.ActorSystemimport akka.actor.Propsclass FirstActor extends Actor with ActorLogging{//通过context.actorOf方法创建Actorval child = context.actorOf(Props[MyActor], name = "myChild")def receive = {case x => child ! x;log.info("received "+x)}}class 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//创建FirstActor对象val myactor = system.actorOf(Props[FirstActor], name = "firstActor")systemLog.info("准备向myactor发送消息")//向myactor发送消息myactor!"test"myactor! 123Thread.sleep(5000)//关闭ActorSystem,停止程序的运行system.shutdown()
}
  • 1

代码运行结果

[INFO] [04/02/2016 15:05:34.770] [main] [ActorSystem(MyActorSystem)] 准备向myactor发送消息
[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

通过代码的运行结果可以看到,FirstActor的Actor路径信息为akka://MyActorSystem/user/firstActor,而通过

class FirstActor extends Actor with ActorLogging{//通过context.actorOf方法创建Actorval child = context.actorOf(Props[MyActor], name = "myChild")def receive = {case x => child ! x;log.info("received "+x)}}

代码使用context.actorOf创建的MyActor,其Actor路径信息为[akka://MyActorSystem/user/firstActor/myChild],这意味着mychild为firstActor的子Actor,层次结构如下图所示

也就是说context.actorOf和system.actorOf的差别是system.actorOf创建的actor为顶级Actor,而context.actorOf方法创建的actor为调用该方法的Actor的子Actor

Akka并发编程——第二节:Actor模型(一)相关推荐

  1. 【Akka】Akka并发编程设计

    1.概述 转载:Akka并发编程设计 2. 响应式系统设计 Akka 被称为是一个响应式平台,更具体的说,它是 Typesafe 响应式平台的一部分.响应式宣言中包含了 4 个准则,也可以说是设计目标 ...

  2. Java并发编程|第二篇:线程生命周期

    文章目录 系列文章 1.线程的状态 2.线程生命周期 3.状态测试代码 4.线程终止 4.1 线程执行完成 4.2 interrupt 5.线程复位 5.1interrupted 5.2抛出异常 6. ...

  3. 网络编程第二节之设备之间的通信(TCP/IP)

    网络编程第二节 单向通信 双向通信---- 较复杂的双向通信---- 单向通信 这算时间在不断学习,发现越发内卷,都说程序员是新一代农民工,现在只能多搬搬砖了- 我们几乎每天都在上网,普通人只知道上网 ...

  4. Akka并发编程——第七节:Actor模型(六)

    主要内容: 1. Typed Actor定义 2. Typed Actor创建 3. 消息发送 1. Typed Actor定义 Akka中的Typed Actor是Active Objects设计模 ...

  5. Akka并发编程——第六节:Actor模型(五)

    本章主要内容: 1. !消息发送,Fire-and-Forget消息模型 2. ?消息发送,Send-And-Receive-Future消息模型 Akka提供了两种消息模型:fire-and-for ...

  6. 并发机制:CSP vs Actor模型以及Golang实现

    作者:花与火山石 原文链接:https://blog.csdn.net/qq_32702033/article/details/104415434 CSP & Actor Model 本文将简 ...

  7. [并发编程]并发编程第二篇:利用并发编程,实现计算大量数据的和

    利用并发编程,实现计算大量数据的和 实现代码: package tj.pojo.generate.main;import java.util.ArrayList; import java.util.L ...

  8. 并发编程——进程——生产者消费者模型

    一.生产者消费者模型介绍 为什么要使用生产者消费者模型 生产者指的是生产数据的任务,消费者指的是处理数据的任务. 在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者 ...

  9. Akka并发编程——第五节:Actor模型(四) 停止Actor

    本节主要内容: 1. 停止Actor 1. 停止Actor (1)通过ActorSystem.shutdown方法停止所有 Actor的运行 /* *停止Actor:ActorSystem.shutd ...

最新文章

  1. hibernate jar包_源码分析 | 咋嘞?你的IDEA过期了吧!加个Jar包就破解了为什么?
  2. c++11的10个新特性
  3. 解决Mac上VSCdoe断点失效问题
  4. leetcode第一刷_Construct Binary Tree from Inorder and Postorder Traversal
  5. InterruptedException和中断线程的解释
  6. Laravel 清空配置缓存
  7. 电力电子技术 matlab仿真指导,在_电力电子技术_课程教学中展开Matlab仿真训练_唐贤伦...
  8. Buttons——CSS按钮样式库
  9. BlackBerry 应用程序开发者指南 第二卷:高级--第7章 与BlackBerry应用程序通信
  10. 第一次失效_直击震撼场面!宁乡新沩丰坝建成以来第一次高水位应急演练!
  11. 送给小白的 7 个 python 小坑
  12. php视图,PHP的Yii框架中View视图的使用进阶
  13. oracle asm查看大小,Oracle ASM查看信息
  14. 微信端input输入框在ios手机上连续输入卡顿
  15. adb 重命名_adb 常用命令-转载
  16. 【转】谷俊丽:基于大数据的深度学习
  17. matlab产生对称矩阵
  18. java 多线程 数据重复,java 多线程 出现数据重复调用有关问题
  19. mysql培训素材总结
  20. (附源码)计算机毕业设计SSM健身房管理系统

热门文章

  1. 《数据结构》c语言版学习笔记——其他链表(线性表的链式存储结构Part2)
  2. maven依赖 spark sql_使用Kafka+Spark+Cassandra构建实时处理引擎
  3. idea新建springboot后端到前端_码云开源项目:利用SpringBoot+Vue 实现留言版
  4. mysql启动主机挂了_docker 启动mysql 挂载宿主机目录
  5. /etc/rc.local——开机自启配置文件
  6. 滑动窗口算法_有点难度,几道和「滑动窗口」有关的算法面试题
  7. mysql long raw_读取Oracle数据库中LONG RAW字段会抛出异常
  8. python商城源码_腾讯大佬用了12小时讲完的Python,整整400集,拿走不谢
  9. 用python批量创建docker_「docker实战篇」python的docker-docker镜像的创建使用dockerfile(3...
  10. 两个gcc_KDD 2020 | GCC:图上的Contrastive Coding