Akka Internal - (Akkaの内部動作を知る) Actorのreceiveメソッドはどのように呼ばれるか?
Akkaの!メソッドでメッセージを「受け取る」側の動作はどうなっているのか?
前回の記事ではAkkaの!メソッドでメッセージを「送る側」の動作が完全なNon-Blockingであることを確認しました。
今回はメッセージを受け取る側、すなわちActorのreceiveメソッドがどのように呼ばれるのかを見ていきます。
def receive = {
...
}
Actorのreceiveメソッド内にブレークポイントを置いてデバッグすると、一番最初にJavaのForkJoinWorkerThreadが動いていることがわかる
Actorのreceiveメソッドはメッセージを送る側(この記事の場合mainスレッド)とは別のスレッドで動きます。その際にForkJoinWorkerThreadを使っているのですね。
Image courtesy of digitalart at FreeDigitalPhotos.net
//scala.concurrent.forkjoin.ForkJoinWorkerThread
public void run() {
...
this.pool.runWorker(this.workQueue);
}
さらにここから、MailboxクラスのprocessMailbox()というメソッドが呼ばれているのがわかります。前回の記事で見たように、MailboxはMessaging Queueを持っていて、これがNon-Blocking (lock-free) queueになっています。
//akka.dispatch.Mailbox
override final def run(): Unit = {
try {
...
processMailbox() //Then deal with messages
...
}
}
というわけで、このMessaging QueueはmainスレッドからもActorが動いている別スレッドからもアクセスされる、スレッド間共有オブジェクトです。
processMailbox()メソッドの中身は以下のようになっています。"next"というのはここではMessaging Queueから取り出したメッセージになっていて、actor (ActorCell)のinvokeメソッドはActorのreceiveメソッドを呼び出すようになっています。
//akka.dispatch.Maibox
@tailrec private final def processMailbox(
...
if (shouldProcessMessage) {
val next = dequeue()
...
actor invoke next
...
}
}