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 模型的消息机制(对应上图)
- 一个消息就是一个Message对象,Message继承了Runable,因此Message就是线程类
- 编程时只需要编写Actor就可以,剩余Actor模型回自动完成
- 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 转发)