Akka并发编程框架

Akka并发编程框架

1. Akka特性

Akka是一个用于构造高并发,分布式和可扩展的基于事件驱动的应用的工具包,Akka是使用scala开发的库,同时可以使用scala和java语言来开发基于Akka的应用程序

2. Akka特性
  • 提供基于异步非阻塞,高性能的事件驱动编程模型
  • 内置容错机制,允许Actor在出错的时候进行恢复或者重置操作
  • 超级轻量级的事件处理(每GB堆内存几百万的Actor)
  • 使用Akka可以在单机上构建高并发程序,也可以在网络中构建分布式程序
3. Akka通信过程

以下图片说明了Akka Actor的并发编程模型的基本流程:

  1. 学生创建一个ActorSystem
  2. 通过ActorSystem来创建一个ActorRef(老师的引用),并将消息发送给ActorRef
  3. ActorRef将消息发送给Message Dispatcher(消息分发器)
  4. Message Dispatcher将消息按照顺序保存到目标Actor的MailBox中
  5. Message Dispatcher将MailBox放到一个线程中
  6. MailBox按照顺序取出消息,最终将它递给TeacherActor接受的方法中
    在这里插入图片描述
4.创建Actor

Akka中.也是基于Actor来进行编程,只是有点小区别

5.API介绍

ActorSystem

  • 在Akka中,ActorSystem是一个重量级的结构,它需要分配多个线程,ActorSystem通常是一个单例对象,可以使用这个ActorSystem创建多个
  • Actor,它只是负责创建和监督actor

Actor中获取ActorSystem

  • 直接使用context.system就可以获取到管理该Actor的ActorSystem的引用

实现Actor类:

  • 继承Actor(导入akka.actor下的Actor)
  • 实现receive方法,在receive方法中直接处理消息,不需要添加loop和react方法调用,Akka会自动调用receive来接收消息
    **[可选]**还可以实现perStart()方法,该方法在Actor对象构建之后执行,在Actor生命周期中仅执行一次

加载Akka Actor

  • 要创建Akka的Actor,必须要先获取创建一个ActorSystem,需要给ActorSystem指定一个名称,并且可以去加载一些配置项
  • 调用ActorS.actorOf(Props(Actor对象),“Actor名字”)来加载Actor

Actor Path
在每一个Actor都有一个Path,路径格式如下:

Actor类型路径示例
本地Actorakka://actorSystem名称/user/Actor名称akka://SimpleAkkaDemo/user/senderActor
远程Actorakka.tcp://my-sys@ip地址:port/user/Actor名称akka.tcp://192.168.10.17:5678/user/service-b
6. 入门案例

基于Akka创建两个Actor,Actor之间可以相互发送消息
在这里插入图片描述
创建并加载Actor

  • 创建两个Actor
    - SenderActor:用来发送消息
    - ReceiveActor:用来接收,回复消息
  • 创建Actor
    - 创建ActorSys
    - 创建自定义Actor
    - ActorSystem加载Actor

发送/接收消息

  • 使用样例类封装消息
  • SubmitTaskMessage----提交任务消息
  • SussessSubmitTaskMessage----任务提交成功消息

参考代码

SimpleAkkaDemo

import akka.actor.{ActorSystem, Props}
import com.typesafe.config.ConfigFactory

object SimpleAkkaDemo {
  case class SubmitTaskMessage(msg:String)//提交任务消息
  case class SuccessSubmitTaskMessage(msg:String)//任务提交成功消息
  def main(args: Array[String]): Unit = {
    val actorSystem = ActorSystem("actorSystem",ConfigFactory.load())
    val senderActor = actorSystem.actorOf(Props(SenderActor),"senderActor")
    val receiverActor = actorSystem.actorOf(Props(ReceiverActor),"receiverActor")
    senderActor ! "start"
  }
}

SenderActor

import SimpleAkkaDemo.{SubmitTaskMessage, SuccessSubmitTaskMessage}
import akka.actor.Actor

object SenderActor extends Actor{
  override def receive: Receive = {
    case "start"=>{
      //path路径格式为: akka://ActorSystem的名字/user/接收消息的Actor名字
      val receiverActor=context.actorSelection("akka://actorSystem/user/receiverActor")
      receiverActor ! SubmitTaskMessage("提交任务信息,发送消息")
   }
    case SuccessSubmitTaskMessage(msg)=>println(s"SenderActor接收到:${msg}")
  }
}

ReceiverActor

import SimpleAkkaDemo.{SubmitTaskMessage, SuccessSubmitTaskMessage}
import akka.actor.Actor

object ReceiverActor  extends Actor{
  override def receive: Receive = {
    case SubmitTaskMessage(msg)=>{
      println(s"ReceiverActor,接收到的消息是${msg}")
      val senderActor = context.actorSelection("akka://actorSystem/user/senderActor")
      senderActor ! SuccessSubmitTaskMessage("提交任务后回执信息,任务提交成功")
    }
  }
}

程序输出:

ReceiverActor,接收到的消息是提交任务信息,发送消息
SenderActor接收到:提交任务后回执信息,任务提交成功
7.Akka定时任务

Akka中,提供了一个scheduler对象来实现定时调度功能,

schedule方法针对scala提供了两种形式:

第一种:发送消息:

def schedule(
    initialDelay: FiniteDuration,		// 延迟多久后启动定时任务
    interval: FiniteDuration,			// 每隔多久执行一次
    receiver: ActorRef,					// 给哪个Actor发送消息
    message: Any)						// 要发送的消息
(implicit executor: ExecutionContext)	// 隐式参数:需要手动导入

第二种:自定义实现

def schedule(
    initialDelay: FiniteDuration,			// 延迟多久后启动定时任务
    interval: FiniteDuration				// 每隔多久执行一次
)(f: ⇒ Unit)								// 定期要执行的函数,可以将逻辑写在这里
(implicit executor: ExecutionContext)		// 隐式参数:需要手动导入

示例一

示例说明

  • 定义一个Actor,每1秒发送一个消息给Actor,Actor收到后打印消息
  • 使用发送消息方式实现

参考代码

import akka.actor.{Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory

object ActorDemo {
  // 1. 创建一个Actor,用来接收消息,打印消息
  object ReceiverActor extends Actor {
    override def receive: Receive = {
      case x=>println(x)
    }
  }
  def main(args: Array[String]): Unit = {
    val actorSystem = ActorSystem("actorSystem",ConfigFactory.load())
    val receiveActor = actorSystem.actorOf(Props(ReceiverActor))
    // 导入一个隐式转换
    import scala.concurrent.duration._
    // 导入隐式参数
    import actorSystem.dispatcher
    actorSystem.scheduler.schedule(0 seconds,1 seconds,receiveActor,"hello")
  }
}

示例二

示例说明

  • 定义一个Actor,每1秒发送一个消息给Actor,Actor收到后打印消息
  • 使用自定义方式实现

参考代码

import akka.actor.{Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory

object SechdulerActor extends Actor{
  override def receive: Receive = {
    case "timer"=>println("收到消息....")
  }
}
object ActorDemo1 {
  def main(args: Array[String]): Unit = {
    val actorSystem = ActorSystem("actorSystem",ConfigFactory.load())
    val sechdulerActor = actorSystem.actorOf(Props(SechdulerActor),"sechdulerActor")
    import scala.concurrent.duration._
    import actorSystem.dispatcher
    actorSystem.scheduler.schedule(0 seconds,1 seconds){
      sechdulerActor ! "timer"
    }
  }
}

注意:

  • 需要导入隐式转换import scala.concurrent.duration._才能调用0 seconds方法
  • 需要导入隐式参数import actorSystem.dispatcher才能启动定时任务
8.实现两个进程之间的通信

基于Akka实现两个进程间发送,接收消息,Worker启动后去连接Master,并发送消息,Master接收到消息后,在回复给Worker

在这里插入图片描述
整体架构
在这里插入图片描述
Akka进程间通信-Worker实现

步骤:
创建一个Maven模块,导入**依赖(附件)**和配置文件

  • 创建Maven模块.
    GroupId: com.csdn
    ArtifactID: akka-worker
  • 在src/main/resources文件夹下创建application.conf
  • 在pom.xml中添加依赖
  • 添加配置信息,修改端口为127.0.0.1:9999

创建启动WorkerActor

  • 在src/main/scala文件夹下创建包: akka
  • 在该包下创建 WorkerActor. //单例对象的形式创建.
  • 在该包下创建Entrance单例对象, 里边定义main方法

发送"setup"消息给WorkerActor,WorkerActor接收打印消息

启动测试

application.conf

akka.actor.provider = "akka.remote.RemoteActorRefProvider"
akka.remote.netty.tcp.hostname = "127.0.0.1"
akka.remote.netty.tcp.port = "9999"

参考代码:

Worker

package akka

import akka.actor.{ActorSystem, Props}
import com.typesafe.config.ConfigFactory

object Worker {
  def main(args: Array[String]): Unit = {
    //创建ActorSystem.
    val actorSystem = ActorSystem("actorSystem",ConfigFactory.load())
    //通过ActorSystem, 加载自定义的WorkActor.
    val workeractor = actorSystem.actorOf(Props(WorkerActor),"workeractor")
    // 给WorkActor发送一句话.
    workeractor ! "setup"
  }
}

WorkerActor

package akka
import akka.actor.Actor
//akka.tcp://actorSystem@127.0.0.1:9999
object WorkerActor extends Actor{
  override def receive = {
    //打印接收到的消息
    case "setup"=>println("WorkerActor 接收到的消息是:setup")
    // 获取MasterActor的引用.
    //格式: akka.tcp://ip地址/user/要获取的actor的名字.
    val masterActor = context.actorSelection("akka.tcp://actorSystem@127.0.0.1:8888/user/masterActor")
    //给MasterActor发送消息.
    masterActor ! "Connect"
    //接收MasterActor回复的消息.
    case "Success"=>println("WorkerActor 接收到回应消息是 Sucess!")
  }
}

程序输出结果

D:\develop\jdk1.8.0_181\bin\java "-javaagent:D:\IntelliJ IDEA 2017.3.2\lib\idea_rt.jar=50825:D:\IntelliJ IDEA 2017.3.2\bin" -Dfile.encoding=UTF-8 -classpath D:\develop\jdk1.8.0_181\jre\lib\charsets.jar;D:\develop\jdk1.8.0_181\jre\lib\deploy.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\dnsns.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\jaccess.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\localedata.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\nashorn.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\sunec.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\zipfs.jar;D:\develop\jdk1.8.0_181\jre\lib\javaws.jar;D:\develop\jdk1.8.0_181\jre\lib\jce.jar;D:\develop\jdk1.8.0_181\jre\lib\jfr.jar;D:\develop\jdk1.8.0_181\jre\lib\jfxswt.jar;D:\develop\jdk1.8.0_181\jre\lib\jsse.jar;D:\develop\jdk1.8.0_181\jre\lib\management-agent.jar;D:\develop\jdk1.8.0_181\jre\lib\plugin.jar;D:\develop\jdk1.8.0_181\jre\lib\resources.jar;D:\develop\jdk1.8.0_181\jre\lib\rt.jar;E:\a黑马javaweb视频\code\ScalaDSJ32\akka-master\target\classes;D:\develop\apache-maven-3.3.9-bin\repository_maven\org\scala-lang\scala-library\2.11.8\scala-library-2.11.8.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\com\typesafe\akka\akka-actor_2.11\2.3.14\akka-actor_2.11-2.3.14.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\com\typesafe\config\1.2.1\config-1.2.1.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\com\typesafe\akka\akka-remote_2.11\2.3.14\akka-remote_2.11-2.3.14.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\io\netty\netty\3.8.0.Final\netty-3.8.0.Final.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\com\google\protobuf\protobuf-java\2.5.0\protobuf-java-2.5.0.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\org\uncommons\maths\uncommons-maths\1.2.2a\uncommons-maths-1.2.2a.jar akka.Master
[INFO] [11/04/2019 01:27:37.411] [main] [Remoting] Starting remoting
[INFO] [11/04/2019 01:27:38.090] [main] [Remoting] Remoting started; listening on addresses :[akka.tcp://actorSystem@127.0.0.1:8888]
[INFO] [11/04/2019 01:27:38.091] [main] [Remoting] Remoting now listens on addresses: [akka.tcp://actorSystem@127.0.0.1:8888]
MasterActor 接收到的消息是:Connect

Akka进程间通信-Master实现

步骤:
创建一个Maven模块,导入依赖和配置文件

  • 创建Maven模块.
    GroupId: com.csdn
    ArtifactID: akka-master
  • 在src/main/resources文件夹下创建application.conf
  • 在pom.xml中添加依赖
  • 添加配置信息,修改端口为127.0.0.1:8888

创建启动MasterActor

  • 在src/main/scala文件夹下创建包: akka
  • 在该包下创建 MasterActor. //单例对象的形式创建.
  • 在该包下创建Entrance单例对象, 里边定义main方法

WorkerActor发送"connect"消息给MasterActor
MasterActor回复"success"消息给WorkerActor
WorkerActor接收并打印接收到的消息
启动Master、Worker测试

application.conf

akka.actor.provider = "akka.remote.RemoteActorRefProvider"
akka.remote.netty.tcp.hostname = "127.0.0.1"
akka.remote.netty.tcp.port = "8888"

参考代码:

Master

package akka

import akka.actor.{ActorSystem, Props}
import com.typesafe.config.ConfigFactory

object Master {
  def main(args: Array[String]): Unit = {
    // 创建ActorSystem.
    val actorSystem = ActorSystem("actorSystem",ConfigFactory.load())
    // 通过ActorSystem, 关联MasterActor.
    val masterActor = actorSystem.actorOf(Props(MasterActor),"masterActor")
  }
}

MasterActor

package akka

import akka.actor.Actor
//akka.tcp://actorSystem@127.0.0.1:8888
object MasterActor extends Actor{
  override def receive = {
    // 打印接收到的消息
    case "Connect"=>println("MasterActor 接收到的消息是:Connect")
    //获取WorkerActor的引用.
    val workerActor = context.actorSelection("akka.tcp://actorSystem@127.0.0.1:9999/user/workeractor")
    //给WorkerActor回复一句话.
    workerActor !"Success"
  }
}

程序输出结果

D:\develop\jdk1.8.0_181\bin\java "-javaagent:D:\IntelliJ IDEA 2017.3.2\lib\idea_rt.jar=50843:D:\IntelliJ IDEA 2017.3.2\bin" -Dfile.encoding=UTF-8 -classpath D:\develop\jdk1.8.0_181\jre\lib\charsets.jar;D:\develop\jdk1.8.0_181\jre\lib\deploy.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\dnsns.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\jaccess.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\localedata.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\nashorn.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\sunec.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;D:\develop\jdk1.8.0_181\jre\lib\ext\zipfs.jar;D:\develop\jdk1.8.0_181\jre\lib\javaws.jar;D:\develop\jdk1.8.0_181\jre\lib\jce.jar;D:\develop\jdk1.8.0_181\jre\lib\jfr.jar;D:\develop\jdk1.8.0_181\jre\lib\jfxswt.jar;D:\develop\jdk1.8.0_181\jre\lib\jsse.jar;D:\develop\jdk1.8.0_181\jre\lib\management-agent.jar;D:\develop\jdk1.8.0_181\jre\lib\plugin.jar;D:\develop\jdk1.8.0_181\jre\lib\resources.jar;D:\develop\jdk1.8.0_181\jre\lib\rt.jar;E:\a黑马javaweb视频\code\ScalaDSJ32\akka-worker\target\classes;D:\develop\apache-maven-3.3.9-bin\repository_maven\org\scala-lang\scala-library\2.11.8\scala-library-2.11.8.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\com\typesafe\akka\akka-actor_2.11\2.3.14\akka-actor_2.11-2.3.14.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\com\typesafe\config\1.2.1\config-1.2.1.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\com\typesafe\akka\akka-remote_2.11\2.3.14\akka-remote_2.11-2.3.14.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\io\netty\netty\3.8.0.Final\netty-3.8.0.Final.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\com\google\protobuf\protobuf-java\2.5.0\protobuf-java-2.5.0.jar;D:\develop\apache-maven-3.3.9-bin\repository_maven\org\uncommons\maths\uncommons-maths\1.2.2a\uncommons-maths-1.2.2a.jar akka.Worker
[INFO] [11/04/2019 01:27:41.493] [main] [Remoting] Starting remoting
[INFO] [11/04/2019 01:27:42.150] [main] [Remoting] Remoting started; listening on addresses :[akka.tcp://actorSystem@127.0.0.1:9999]
[INFO] [11/04/2019 01:27:42.151] [main] [Remoting] Remoting now listens on addresses: [akka.tcp://actorSystem@127.0.0.1:9999]
WorkerActor 接收到的消息是:setup
WorkerActor 接收到回应消息是 Sucess!

附件(maven依赖)

<properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <encoding>UTF-8</encoding>
        <scala.version>2.11.8</scala.version>
        <scala.compat.version>2.11</scala.compat.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>${scala.version}</version>
        </dependency>

        <dependency>
            <groupId>com.typesafe.akka</groupId>
            <artifactId>akka-actor_2.11</artifactId>
            <version>2.3.14</version>
        </dependency>

        <dependency>
            <groupId>com.typesafe.akka</groupId>
            <artifactId>akka-remote_2.11</artifactId>
            <version>2.3.14</version>
        </dependency>

    </dependencies>

    <build>
        <sourceDirectory>src/main/scala</sourceDirectory>
        <testSourceDirectory>src/test/scala</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>3.2.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                        <configuration>
                            <args>
                                <arg>-dependencyfile</arg>
                                <arg>${project.build.directory}/.scala_dependencies</arg>
                            </args>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                    <resource>reference.conf</resource>
                                </transformer>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass></mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值