Actor模型原理

1.Actor模型

在使用Java进行并发编程时须要特别的关注锁和内存原子性等一系列线程问题,而Actor模型内部的状态由它本身维护即它内部数据只能由它本身修改(经过消息传递来进行状态修改),因此使用Actors模型进行并发编程能够很好地避免这些问题,Actor由状态(state)、行为(Behavior)和邮箱(mailBox)三部分组成html

  1. 状态(state):Actor中的状态指的是Actor对象的变量信息,状态由Actor本身管理,避免了并发环境下的锁和内存原子性等问题
  2. 行为(Behavior):行为指定的是Actor中计算逻辑,经过Actor接收到消息来改变Actor的状态
  3. 邮箱(mailBox):邮箱是Actor和Actor之间的通讯桥梁,邮箱内部经过FIFO消息队列来存储发送方Actor消息,接受方Actor从邮箱队列中获取消息

Actor的基础就是消息传递

2.使用Actor模型的好处:

  1. 事件模型驱动--Actor之间的通讯是异步的,即便Actor在发送消息后也无需阻塞或者等待就可以处理其余事情
  2. 强隔离性--Actor中的方法不能由外部直接调用,全部的一切都经过消息传递进行的,从而避免了Actor之间的数据共享,想要
    观察到另外一个Actor的状态变化只能经过消息传递进行询问
  3. 位置透明--不管Actor地址是在本地仍是在远程机上对于代码来讲都是同样的
  4. 轻量性--Actor是很是轻量的计算单机,单个Actor仅占400多字节,只需少许内存就能达到高并发

3.Actor模型原理

如下经过学生与教师之间的邮件通讯来理解akka中的Actor模型编程

学生-教师的消息传递

首先先只考虑学生单向发送消息给教师(学生--->教师),以下图:
并发

图解:app

  1. 学生建立一个ActorSystem
  2. 经过ActorSystem建立ActorRef,将QuoteRequest消息发送到ActorRef(教师代理)
  3. ActorRef(教师代理)消息传递到Dispatcher中
  4. Dispatcher依次的将消息发送到TeacherActor的邮箱中
  5. Dispatcher将邮箱推送到一条线程中
  6. 邮箱取出一条消息并委派给TeacherActor的receive方法

下面再详细的解释每一步骤框架

StudentSimulatorApp主程序详解:

首先StudentSimulatorApp会先启动JVM并初始化ActorSystem
dom

如上图所示,StudentSimulatorApp的主要工做为:异步

  1. 建立ActorSystem
    • ActorSystem做为顶级Actor,能够建立和中止Actors,甚至可关闭整个Actor环境,
      此外Actors是按层次划分的,ActorSystem就比如Java中的Object对象,Scala中的Any,
      是全部Actors的根,当你经过ActorSystem的actof方法建立Actor时,实际就是在ActorSystem
      下建立了一个子Actor。
      可经过如下代码来初始化ActorSystemide

      val system = ActorSystem("UniversityMessageSystem")高并发

  2. 经过ActorSystem建立TeacherActor的代理(ActorRef)
    • 看看TeacherActor的代理的建立代码ui

      val teacherActorRef:ActorRef = system.actorOf(Props[TeacherActor])

    ActorSystem经过actorOf建立Actor,但其并不返回TeacherActor而是返
    回一个类型为ActorRef的东西。
    ActorRef做为Actor的代理,使得客户端并不直接与Actor对话,这种Actor
    模型也是为了不TeacherActor的自定义/私有方法或变量被直接访问,所
    以你最好将消息发送给ActorRef,由它去传递给目标Actor
  3. 发送QuoteRequest消息到代理中
    • 你只需经过!方法将QuoteReques消息发送给ActorRef(注意:ActorRef也有个tell方法,其做用就委托回调给!)

      techerActorRef!QuoteRequest
      等价于teacherActorRef.tell(QuoteRequest, teacherActorRef)

完整StudentSimulatorApp代码

object StudentSimulatorApp extends App{
 //初始化ActorSystem
 val actorSystem=ActorSystem("UniversityMessageSystem")
 //构建teacherActorRef
 val teacherActorRef=actorSystem.actorOf(Props[TeacherActor])
 //发送消息给TeacherActor
 teacherActorRef! QuoteRequest
 Thread.sleep (2000)
 //关闭 ActorSystem,若是不关闭JVM将不会退出
 actorSystem.shutdown()
}

QuoteRequest类

object TeacherProtocol{
 case class QuoteRequest() //请求
 case class QuoteResponse(quoteString:String) //响应
}

Dispatcher和MailBox

ActorRef将消息处理能力委派给Dispatcher,实际上,当咱们建立ActorSystem和ActorRef时,
Dispatcher和MailBox就已经被建立了

  • MailBox

    • 每一个Actor都有一个MailBox,一样,Teacher也有个MailBox,其会检查MailBox并处理消息。
      MailBox内部采用的是FIFO队列来存储消息,有一点不一样的是,现实中咱们的最新邮件
      会在邮箱的最前面。
  • Dispatcher

    • Dispatcher从ActorRef中获取消息并传递给MailBox,Dispatcher封装了一个线程池,以后在
      线程池中执行MailBox。

      protected[akka] override def registerForExecution(mbox: Mailbox, ...): Boolean = {
        ...
       try {
       executorService execute mbox
       ...
      }

    • 为何能执行MailBox?
      • 看看MailBox的实现,没错,其实现了Runnable接口

        private[akka] abstract class Mailbox(val messageQueue: MessageQueue) extends SystemMessageQueue with Runnable

TeacherActor

  • 当ActorRef发送消息调用目标Actor的reveive方法时,MailBox中的run方法被执行,接着从消息队列中取出一条消息并传递给Actor处理

    class TeacherActor extends Actor {
     val quotes = List(
      "Moderation is for cowards",
      "Anything worth doing is worth overdoing",
      "The trouble is you think you have time",
      "You never gonna know if you never even try")
     def receive = {
      case QuoteRequest => {
      import util.Random
      //从list中随机选出一条消息做为回应(这里只print并没回应学生的请求)
      val quoteResponse=QuoteResponse(quotes(Random.nextInt(quotes.size)))
      println (quoteResponse)
      }
     }
    }
    TeacherActor的receive方法将匹配QuoteRequest消息

这里有个国外博主写的Akka系列博客都很赞,分享给你们!

本文参考资料

AKKA NOTES - ACTOR MESSAGING - 1
Akka框架——第一节:并发编程简介
Akka Quickstart with Scala

相关文章
相关标签/搜索