Scala 速通语法(十四)| Akka并发编程模型

Akka并发编程模型

Akka介绍

  • Akka 是 JAVA 虚拟机 JVM 平台上构建高并发、分布式和容错应用的工具包和运行时,可以理解成 Akka 是编写并发程序的框架。
  • Akka 用 Scala 语言写成,同时提供了 Scala 和 JAVA 的开发接口。
  • Akka 主要解决的问题是:可以轻松的写出高效稳定的并发程序,程序员不再过多的考虑线程、锁和资源竞争等细节

Actor 模型用于解决什么问题

  • 处理并发问题关键是要保证共享数据的一致性和正确性,多个线程对同一个数据进行修改,若不加同步条件,势必会造成数据污染。当对关键代码加入同步条件 synchronized 后,大并发就会阻塞在这段代码,对程序效率影响很大
  • 若是用单线程处理,不会有数据一致性的问题,但是系统的性能又不能保证
  • Actor 模型的出现解决了这个问题,简化并发编程,提升程序性能

Akka 中 Actor 模型

  • Akka 处理并发的方法基于 Actor 模型。(示意图)
  • 在基于 Actor 的系统里,所有的事物都是 Actor,就好像在面向对象设计里面所有的事物都是对象一样
  • Actor 模型是作为一个并发模型设计和架构的。Actor 与 Actor 之间只能通过消息通信,如图的信封
  • Actor 与 Actor 之间只能用消息进行通信,当一个 Actor 给另外一个 Actor 发消息,消息是有顺序的(消息队列),只需要将消息投寄的相应的邮箱即可
  • 怎么处理消息是由接收消息的 Actor 决定的,发送消息 Actor 可以等待回复,也可以异步处理
  • ActorSystem 的 职 责 是 负 责创 建并 管理 其创 建 的 Actor, ActorSystem 是 单例 的( 可以理解为 ActorSystem 是一个工厂,专门创建 Actor),一个 JVM 进程中有一个即可,而 Acotr 是可以有多个的
  • Actor 模型是对并发模型进行了更高的抽象
  • Actor 模型是异步、非阻塞、高性能的事件驱动编程模型
  • Actor 模型是轻量级事件处理(1GB 内存可容纳百万级别个 Actor),因此处理大并发性能高

Actor 模型工作机制说明

  • 说明了 Actor 模型的工作机制(对应上图)

  • ActorySystem 创建 Actor

  • ActorRef:可以理解成是 Actor 的代理或者引用。消息是通过 ActorRef 来发送,而不能通过 Actor 发送消息,通过哪个 ActorRef 发消息,就表示把该消息发给哪个 Actor

  • 消息发送到 Dispatcher Message (消息分发器),它得到消息后,会将消息进行分发到对应的MailBox。(注: Dispatcher Message 可以理解成是一个线程池, MailBox 可以理解成是消息队列,可以缓冲多个消息,遵守 FIFO)

  • Actor 可以通过 receive 方法来获取消息,然后进行处理

  • Actor 模型的消息机制(对应上图)

    1. 一个消息就是一个Message对象,Message继承了Runable,因此Message就是线程类
    2. 编程时只需要编写Actor就可以,剩余Actor模型回自动完成
    3. A Actor 要给B Actor 发送消息,那么A Actor 要先拿到或者持有B Actor的代理对象 B ActorRef

Actor 模型实例

  • 简单实例演示
package com.zhy.chapter18.akka

import akka.actor.{Actor, ActorRef, ActorSystem, Props}

class SayHelloActor extends Actor{
  override def receive: Receive = {
    //1. receive 方法,会被该 Actor 的 MailBox(实现了 Runnable 接口)调用
    //2. 当该 Actor 的 MailBox 接收到消息,就会调用 receive
    //3. type Receive = PartialFunction[Any, Unit]
    case "hello" => println("receive hello")
    case "ok" => println("ok")
    case "exit" => {
      println("接收到 exit 指令,退出系统")
      context.stop(self) //停止 actoref
      context.system.terminate() //退出 actorsystem
    }
    case _ => println("没哦")
  }
}

object SayHelloActor {
  // 创建一个ActorSystem 创建Actor
  val as = ActorSystem ("aaa")
  //2. 创建一个 Actor 的同时,返回 Actor 的 ActorRef
  //说明
  //(1) Props[SayHelloActor] 创建了一个 SayHelloActor 实例,使用反射
  //(2) "sayHelloActor" 给 actor 取名
  //(3) sayHelloActorRef: ActorRef 就是 Props[SayHelloActor] 的 ActorRef
  //(4) 创建的 SayHelloActor 实例被 ActorSystme 接管
  private val sayHelloActorRef: ActorRef = as.actorOf(Props[SayHelloActor], "sayHelloActor")

  def main(args: Array[String]): Unit = {
    //给SayhelloActor发消息
    sayHelloActorRef!"hello"
    sayHelloActorRef!"ok"
    //研究异步如何退出 ActorSystem
    sayHelloActorRef ! "exit"
  }
}
  • 当程序执行 aActorRef = actorFactory.actorOf(Props[AActor], "aActor") ,会完成如下任务
  • actorFactory 是 ActorSystem("ActorFactory") 这样创建的
  • 这 里 的 Props[AActor] 会使用反射机制,创建一个 A Actor 对象,如果是 actorFactory.actorOf(Props(new AActor(bActorRef)), "aActorRef") 形式,就是使用 new 的方式创建一个 AActor 对象, 注意 Props() 是小括号
  • 会创建一个 AActor 对象的代理对象 aActorRef , 使用 aActorRef 才能发送消息
  • 会在底层创建 Dispather Message ,是一个线程池,用于分发消息, 消息是发送到对应的 Actor 的MailBox
  • 会在底层创建 AActor 的 MailBox 对象,该对象是一个队列,可接收 Dispatcher Message 发送的消
  • MailBox 实现了 Runnable 接口,是一个线程,一直运行并调用 Actor 的 receive 方法,因此当Dispather 发送消息到 MailBox 时,Actor 在 receive 方法就可以得到信息
  • aActorRef! "hello", 表示把 hello 消息发送到 AActor 的 mailbox(通过 Dispatcher Message 转发)
posted @ 2021-11-09 16:16  —清风碎心—  阅读(95)  评论(0编辑  收藏  举报