みなさん、Akka使ってますか。AkkaはActorモデルを使った並行処理を簡単に書くためのScalaのライブラリです。
でも私はScalaがあまり好きではないので、Javaから使っています。
AkkaはJava用のインターフェイスとドキュメントもしっかり揃っており、使い勝手はかなり異なりますが、Javaでもほぼ全ての機能を使うことができます。
準備
AkkaのドキュメントGetting startedに則って、SBTを使って必要なライブラリを集めます。SBTのインストール方法や使い方はここでは説明しません。
(http://doc.akka.io/docs/akka/snapshot/intro/getting-started.html)
name := "akka"
version := "1.0"
scalaVersion := "2.11.5"
resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
libraryDependencies ++=
Seq("com.typesafe.akka" % "akka-actor_2.11" % "2.3.9")
Actorの実装
public class EchoActor extends UntypedActor {
public EchoActor() {
System.out.println("constructor");
}
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
System.out.println("Got message. " + message);
getSender().tell(message, getSender());
} else {
System.out.println("Got unknown type message.");
unhandled(message);
}
}
}
まずActorを作ります。akka.actorパッケージのUntypedActorというクラスを継承して、onReceiveというメソッドを実装します。
"Untyped"はOnReceiveメソッドで受け取れるメッセージの型はなんでも良い(Object)であることを示しています。
onReceiveメソッドは、メッセージ(Object)を別のActor等から受け取った時に呼ばれるコールバックメソッドです。
メッセージを受け取っていない時は、特に何もしません。
onReceiveはどんな型のメッセージでも受け取れてしまうため、メッセージの型や中身を見て処理を分岐してあげる必要があります。
Javaにはパターンマッチがないため、このあたりの処理がやや煩雑になりがちです・・・。
public class Main {
public static void main(String[] args) {
ActorSystem system = ActorSystem.create("EchoSystem");
ActorRef echoActorRef = system.actorOf(Props.create(EchoActor.class), "EchoActor");
echoActorRef.tell("Hello world", ActorRef.noSender());
system.stop(echoActorRef);
system.shutdown();
}
}
次に、EchoActorの実体を生成して、Actorにメッセージを送る部分を実装します。今回は安易にmainに実装しました。
ActorSystemは、Actorを管理するためのオブジェクトです。どんなActorもどこかのActorSystemに所属することになります。
ActorSystemは、到来したメッセージを振り分けたり、Actorを動かすためのスレッドプールの管理等をやっているようです。
ActorSystemを生成したあとは、ActorSystemのメソッドであるactorOfを経由してEchoActorの実体を生成し、その参照であるActorRefを得ます。
ActorRef自身はActorの実体を持っておらず、Actorへのアドレスだけを持っています。なぜ参照なのかは色々と事情があります。(今回は説明しません)
3行目で、tellメソッドを使ってEchoActorへメッセージを送信します。tellメソッドは非同期に実行されます。今回はメッセージを送った結果を確認する方法を実装していないので、EchoActorに何が起こったかをmainメソッドの中では知ることはできません。
4,5行目は、Actorの停止とActorSystemの停止処理です。
stopメソッドはActorがメッセージを処理している最中の場合には、それが終わるまで待ってから停止を試みます。(ちゃんとした理由がありますが、今回は説明しません)
また、ActorSystemの停止をするshutdownメソッドはSystemに所属している全てのActorがメッセージを処理し終わるまで待ってから停止を試みます。