Scala 之并发编程模型 Akka

Akka 介绍

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

Actor 模型用于解决什么问题

  1. 处理并发问题关键是要保证共享数据的一致性和正确性,因为程序是多线程时,多个线程对同一个数据进行修改,若不加同步条件,势必会造成数据污染。但是当我们对关键代码加入同步条件 synchronized 后,实际上大并发就会阻塞在这段代码,对程序效率有很大影响。
  2. 若是用单线程处理,不会有数据一致性的问题,但是系统的性能又不能保证。
  3. Actor 模型的出现解决了这个问题,简化并发编程,提升程序性能。你可以这里理解: Actor 模型是一种处理并发问题的解决方案,很牛!

Akka 中 Actor 模型

Scala 之并发编程模型 Akka_第1张图片

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

Actor 模型工作机制:

Scala 之并发编程模型 Akka_第2张图片

从上图看:
Actor模型的工作机制
  1. ActorySystem 创建 Actor
  2. ActorRef: 可以理解成是Actor的代理或者引用。消息是通过ActorRef来发送,而不能通过Actor
    送消息,通过哪个 ActorRef 发消息,就表示把该消息发给哪个 Actor
  3. 消息发送到 Dispatcher Message (消息分发器),它得到消息后,会将消息进行分发到对应的
    MailBox。(注: Dispatcher Message 可以理解成是一个线程池, MailBox 可以理解成是消息队列,可以缓冲多个消息,遵守 FIFO(栈))
  4. Actor 可以通过 receive(Dispatcher调用) 方法来获取消息,然后进行处理。
Actor模型的消息机制
  1. 每一个消息就是一个 Message 对象。Message 继承了 Runable, 因为 Message 就是线程类。
  2. 从 Actor 模型工作机制看上去很麻烦,但是程序员编程时只需要编写 Actor 就可以了,其它的交
    给 Actor 模型完成即可。
  3. A Actor 要给 B Actor 发送消息,那么 A Actor 要先拿到(也称为持有) B Actor 的 代理对象
    ActorRef 才能发送消息
单一Actor通讯案例:
import akka.actor.{
     Actor, ActorRef, ActorSystem, Props}

//说明
//1. 当我们继承 Actor 后,就是一个 Actor,核心方法 receive 方法重写
class SayHelloActor extends Actor {
     
  //说明
  //1. receive 方法,会被该 Actor 的 MailBox(实现了 Runnable 接口)调用 
  //2. 当该 Actor 的 MailBox 接收到消息,就会调用 receive
  //3. type Receive = PartialFunction[Any, Unit]
  override def receive: Receive = {
     
    case "hello" => println("收到 hello, 回应 hello too:)")
    case "ok" => println("收到 ok, 回应 ok too:)")
    case "exit" => {
     
      println("接收到 exit 指令,退出系统")
      context.stop(self) //停止 actoref
      context.system.terminate() //退出 actorsystem
    }
    case _ => println("匹配不到")
  }
}

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

  def main(args: Array[String]): Unit = {
     
    //给 SayHelloActor 发消息(邮箱)
    sayHelloActorRef ! "hello"
    sayHelloActorRef ! "ok"
    sayHelloActorRef ! "ok~"
    sayHelloActorRef ! "exit"
  }
}
  1. 当程序执行 aActorRef = actorFactory.actorOf(Props[AActor], “aActor”) ,会完成如下任务 [这是非常重要的方法]
  1. actorFactory 是 ActorSystem("ActorFactory") 这样创建的。
  2. 这里的 Props[AActor] 会使用反射机制,创建一个 AActor 对象,如果是 actorFactory.actorOf(Props(new AActor(bActorRef)), "aActorRef") 形式,就是使用 new 的方式创建一 个 AActor 对象, 注意 Props() 是小括号。
  3. 会创建一个 AActor 对象的代理对象 aActorRef , 使用 aActorRef 才能发送消息
  4. 会在底层创建 Dispather Message ,是一个线程池,用于分发消息, 消息是发送到对应的 Actor 的 MailBox
  5. 会在底层创建 AActor 的 MailBox 对象,该对象是一个队列,可接收 Dispatcher Message 发送的消 息
  6. MailBox 实现了 Runnable 接口,是一个线程,一直运行并调用 Actor 的 receive 方法,因此当 Dispather 发送消息到 MailBox 时,Actor 在 receive 方法就可以得到信息.
  7. aActorRef ! “hello”, 表示把 hello 消息发送到 A Actor 的 mailbox(通过 Dispatcher Message 转发)

你可能感兴趣的:(Scala,Scala,Akka)