Akka简介以及入门案例
Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和 Scala 的 Actor 模型应用
1.基于Actor的模型,我们大家都知道,在多线程领域,最困难的莫过于并发了,我们一般情况下处理并发会涉及到共享变量的问题,这样很容易造成死锁,模型如下:
而Akka是基于消息的Actor模型,Actor是具有属性和操作的,所有的操作都在Actor自身来完成,所以不存共享数据的问题
这里Actor A和B之间的通信是以消息的方式进行通信,每一个操作都是在Actor的内部完成的,所以不存在资源竞争的问题。
另外,Actor是为分布式的应用服务了
下面看一个例子
首先编写服务端代码:
import akka.actor.ActorSystem import akka.actor.Actor import akka.actor.Props import com.typesafe.config.ConfigFactory import akka.actor.ActorRef object HelloRemote extends App { var akkaConf = ConfigFactory.parseString( s""" |akka.actor.provider = "akka.remote.RemoteActorRefProvider" |akka.remote.netty.tcp.transport-class = "akka.remote.transport.netty.NettyTransport" |akka.remote.netty.tcp.hostname = "127.0.0.1" |akka.remote.netty.tcp.port = 5160 """.stripMargin) val actorSystem = ActorSystem("remotetest", akkaConf) val remoteActor = actorSystem.actorOf(Props[RemoteActor], name = "remoteActor") println(remoteActor) remoteActor.tell("START", ActorRef.noSender) } class RemoteActor extends Actor { def receive = { case "START" => println("RemoteActor started ") case msg: String => println(s"RemoteActor received message '$msg'") sender ! "reply from the RemoteActor" } }
这里RomoteActor是Actor的定义,所有的Actor都要继承Actor
receive 方法为需要自己实现的方法,这个方法内部定义了接收到消息后该做如何的处理
(这里是使用Scala语言实现的,Scala语言和java语言的不同点之一,就是case语句执行后不会继续往下执行)
这里我们定义了两类消息:
消息一:字符串等于START,这样是为了方便启动这个Actor
消息二:字符串类型消息,这样就接收所有的消息,然后进行回复。
sender是发送者actor的句柄,这样就能像发送者返回消息
我们启动这个remoteActor:
可以看到这个Actor已经启动,其中/user/remoteActor是这个actor的访问路径
下面我们编写一个本地端Actor
import akka.actor.Actor import akka.actor.ActorSystem import akka.actor.Props import com.typesafe.config.ConfigFactory import java.io.File import scala.concurrent.Await import scala.concurrent.duration._ import akka.actor.ActorRef object Local extends App { var akkaConf = ConfigFactory.parseString( s""" |akka.actor.provider = "akka.remote.RemoteActorRefProvider" |akka.remote.netty.tcp.transport-class = "akka.remote.transport.netty.NettyTransport" |akka.remote.netty.tcp.hostname = "127.0.0.1" |akka.remote.netty.tcp.port = 0 """.stripMargin) val actorSystem = ActorSystem("local", akkaConf) val localActor1 = actorSystem.actorOf((Props(new LocalActor("localActor1"))), name = "LocalActor1") // the local actor val localActor2 = actorSystem.actorOf((Props(new LocalActor("localActor2"))), name = "LocalActor2") // the local actor val localActor3 = actorSystem.actorOf((Props(new LocalActor("localActor3"))), name = "LocalActor3") // the local actor val localActor4 = actorSystem.actorOf((Props(new LocalActor("localActor4"))), name = "LocalActor4") // the local actor localActor1 ! "START" // start the action localActor2 ! "START" // start the action localActor3 ! "START" // start the action localActor4 ! "START" // start the action } case object Tick class LocalActor(name: String) extends Actor { // create the remote actor val remote = context.actorSelection("akka.tcp://[email protected]:5160/user/remoteActor") var counter = 0 //var tiker = context.system.scheduler.schedule(1 millis, 100 millis)(println("hehheh")) def receive = { case "START" => remote ! "Hello from the LocalActor:" + name case msg: String => println(s"LocalActor received message: '$msg'") if (counter < 5) { sender ! "The " + counter + " message from the LocalActor:" + name counter += 1 } } }
val remote = context.actorSelection("akka.tcp://[email protected]:5160/user/remoteActor")
就是连接远端的actor
我们启动local端,会看到连接信息