最近公司用到spary+akak,然后从官网找了一个入门的例子,现在分析一下
1.简单demo
首先akka给我的感觉就是一个异步的发送消息的机制,如果我用java来解释,那就是重新起一个新线程,然后调用一个类的方法。
//简单定义一些用到的消息类
object Greeter {
//#greeter-messages
def props(message: String, printerActor: ActorRef): Props = Props(new Greeter(message, printerActor))
//#greeter-messages
final case class WhoToGreet(who: String)
case object Greet
}
//继承Actor,实现receive方法,printerActor这也是个actor,这里省略
class Greeter(message: String, printerActor: ActorRef) extends Actor {
import Greeter._
import Printer._
var greeting = ""
def receive = {
case WhoToGreet(who) =>
greeting = message + ", " + who
case Greet =>
//#greeter-send-message
printerActor ! Greeting(greeting)
//#greeter-send-message
}
}
//相当于主函数
object AkkaQuickstart extends App {
import Greeter._
// Create the 'helloAkka' actor system
val system: ActorSystem = ActorSystem("helloAkka")
// Create the 'greeter' actors
val howdyGreeter: ActorRef =system.actorOf(Greeter.props("Howdy", printer), "howdyGreeter")
//#main-send-messages
howdyGreeter ! WhoToGreet("Akka")
howdyGreeter ! Greet
}
2. 分析!是什么
/**
* Sends a one-way asynchronous message. E.g. fire-and-forget semantics.
* <p/>
*
* If invoked from within an actor then the actor reference is implicitly passed on as the implicit 'sender' argument.
* <p/>
*
* This actor 'sender' reference is then available in the receiving actor in the 'sender()' member variable,
* if invoked from within an Actor. If not then no sender is available.
* <pre>
* actor ! message
* </pre>
* <p/>
*/
def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit
fire-and-forget:这个词很生动,也就说调用某个类方法的时候会把调用者的引用传递过去。
3. 深入分析调用过程
一路调试过去,会发现调用Dispatcher这个类
protected[akka] override def registerForExecution(
mbox: Mailbox,
hasMessageHint: Boolean,
hasSystemMessageHint: Boolean): Boolean = {
if (mbox.canBeScheduledForExecution(hasMessageHint, hasSystemMessageHint)) { //This needs to be here to ensure thread safety and no races
if (mbox.setAsScheduled()) {
try {
executorService.execute(mbox)
true
} catch {
case _: RejectedExecutionException =>
try {
executorService.execute(mbox)
true
} catch { //Retry once
case e: RejectedExecutionException =>
mbox.setAsIdle()
eventStream.publish(Error(e, getClass.getName, getClass, "registerForExecution was rejected twice!"))
throw e
}
}
} else false
} else false
}
- 其中
mbox: Mailbox
,消息参数、调用者参数都被封装到这个类中了,到底Mailbox是什么
private[akka] abstract class Mailbox(val messageQueue: MessageQueue)
extends ForkJoinTask[Unit]
with SystemMessageQueue
with Runnable
从中文解释就是一个邮箱,它带有队列功能(MessageQueue),同时它实现了Runnable
和ForkJoinTask
,这个学习java的都很熟悉了,这个就是一个可运行的任务
- executorService.execute(mbox)
这个再熟悉不过了,这个就是线程服务,执行一个可运行的任务。
总结
akak就是一个异步的调用方法的东西,它还是利用java中的executorService来调用,算是一个队多线程的封装把