下面就Akka的一个java demo来说明Akka 如何运作的。
1、首先下载 Akka的官方包
下载地址为: http://akka.io/downloads/. 我下载的是 Akka的2.3.15
解压这个压缩包,准备拷贝相关的jar包到自己的工程
2、创建一个java工程
首先导入包
3、下面是源码和源码说明
这里,首先贴入源码,然后再对源码进行分析。 源码有4个文件,主要完成的功能是,主程序创建ActorSystem,并且生成Actor1(CreationActor),这个Actor1,根据随机得到的消息,循环创建线程,每个线程都创建Actor2(CalculatorActor),并发不同的消息给Actor2 告诉这些第二层Actor要做什么。 这些Actor2 做完自己的事情后,发消息给Actor1,告诉自己完成了,Actor1 收到消息后,打印结果是什么,并结束线程。
整个业务大致可以用下面图来表示:(左边是示意图,右边是类图)
Op.java
<span style="font-family:Microsoft YaHei;font-size:14px;">package com.cwqsolo.study.akka.demo;
import java.io.Serializable;
//Op 类是操作类,分别包含了 加减乘除类和加减乘除结果类
public class Op {
public interface MathOp extends Serializable {
}
public interface MathResult extends Serializable {
}
//加法操作
static class Add implements MathOp {
private static final long serialVersionUID = 1L;
private final int n1;
private final int n2;
public Add(int n1, int n2) {
this.n1 = n1;
this.n2 = n2;
}
public int getN1() {
return n1;
}
public int getN2() {
return n2;
}
}
static class AddResult implements MathResult {
private static final long serialVersionUID = 1L;
private final int n1;
private final int n2;
private final int result;
public AddResult(int n1, int n2, int result) {
this.n1 = n1;
this.n2 = n2;
this.result = result;
}
public int getN1() {
return n1;
}
public int getN2() {
return n2;
}
public int getResult() {
return result;
}
}
//减法操作
static class Subtract implements MathOp {
private static final long serialVersionUID = 1L;
private final int n1;
private final int n2;
public Subtract(int n1, int n2) {
this.n1 = n1;
this.n2 = n2;
}
public int getN1() {
return n1;
}
public int getN2() {
return n2;
}
}
static class SubtractResult implements MathResult {
private static final long serialVersionUID = 1L;
private final int n1;
private final int n2;
private final int result;
public SubtractResult(int n1, int n2, int result) {
this.n1 = n1;
this.n2 = n2;
this.result = result;
}
public int getN1() {
return n1;
}
public int getN2() {
return n2;
}
public int getResult() {
return result;
}
}
//乘法操作
static class Multiply implements MathOp {
private static final long serialVersionUID = 1L;
private final int n1;
private final int n2;
public Multiply(int n1, int n2) {
this.n1 = n1;
this.n2 = n2;
}
public int getN1() {
return n1;
}
public int getN2() {
return n2;
}
}
static class MultiplicationResult implements MathResult {
private static final long serialVersionUID = 1L;
private final int n1;
private final int n2;
private final int result;
public MultiplicationResult(int n1, int n2, int result) {
this.n1 = n1;
this.n2 = n2;
this.result = result;
}
public int getN1() {
return n1;
}
public int getN2() {
return n2;
}
public int getResult() {
return result;
}
}
// 除法操作
static class Divide implements MathOp {
private static final long serialVersionUID = 1L;
private final double n1;
private final int n2;
public Divide(double n1, int n2) {
this.n1 = n1;
this.n2 = n2;
}
public double getN1() {
return n1;
}
public int getN2() {
return n2;
}
}
static class DivisionResult implements MathResult {
private static final long serialVersionUID = 1L;
private final double n1;
private final int n2;
private final double result;
public DivisionResult(double n1, int n2, double result) {
this.n1 = n1;
this.n2 = n2;
this.result = result;
}
public double getN1() {
return n1;
}
public int getN2() {
return n2;
}
public double getResult() {
return result;
}
}
}</span>
CalculatorActor.java
<span style="font-family:Microsoft YaHei;font-size:14px;">package com.cwqsolo.study.akka.demo;
import akka.actor.UntypedActor;
public class CalculatorActor extends UntypedActor {
@Override
public void onReceive(Object message) {
if (message instanceof Op.Add) {
Op.Add add = (Op.Add) message;
System.out.println("Calculating " + add.getN1() + " + " + add.getN2());
Op.AddResult result = new Op.AddResult(add.getN1(), add.getN2(),
add.getN1() + add.getN2());
getSender().tell(result, getSelf());
} else if (message instanceof Op.Subtract) {
Op.Subtract subtract = (Op.Subtract) message;
System.out.println("Calculating " + subtract.getN1() + " - "
+ subtract.getN2());
Op.SubtractResult result = new Op.SubtractResult(subtract.getN1(),
subtract.getN2(), subtract.getN1() - subtract.getN2());
getSender().tell(result, getSelf());
} else if (message instanceof Op.Multiply) {
Op.Multiply multiply = (Op.Multiply) message;
System.out.println("Calculating " + multiply.getN1() + " * "
+ multiply.getN2());
Op.MultiplicationResult result = new Op.MultiplicationResult(
multiply.getN1(), multiply.getN2(), multiply.getN1()
* multiply.getN2());
getSender().tell(result, getSelf());
} else if (message instanceof Op.Divide) {
Op.Divide divide = (Op.Divide) message;
System.out.println("Calculating " + divide.getN1() + " / "
+ divide.getN2());
Op.DivisionResult result = new Op.DivisionResult(divide.getN1(),
divide.getN2(), divide.getN1() / divide.getN2());
getSender().tell(result, getSelf());
} else {
unhandled(message);
}
}
}</span>
CreationActor.java
<span style="font-family:Microsoft YaHei;font-size:14px;">package com.cwqsolo.study.akka.demo;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedActor;
//创建Actor
public class CreationActor extends UntypedActor {
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof Op.MathOp) {
ActorRef calculator = getContext().actorOf(
Props.create(CalculatorActor.class));
calculator.tell(message, getSelf());
} else if (message instanceof Op.MultiplicationResult) {
Op.MultiplicationResult result = (Op.MultiplicationResult) message;
System.out.printf("Mul result: %d * %d = %d\n", result.getN1(),
result.getN2(), result.getResult());
getContext().stop(getSender());
} else if (message instanceof Op.DivisionResult) {
Op.DivisionResult result = (Op.DivisionResult) message;
System.out.printf("Div result: %.0f / %d = %.2f\n", result.getN1(),
result.getN2(), result.getResult());
getContext().stop(getSender());
} else {
unhandled(message);
}
}
}</span>
CreationApplication.java
<span style="font-family:Microsoft YaHei;font-size:14px;">package com.cwqsolo.study.akka.demo;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.Random;
import scala.concurrent.duration.Duration;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import com.typesafe.config.ConfigFactory;
public class CreationApplication {
public static void main(String[] args) {
if (args.length == 0 || args[0].equals("CalculatorWorker"))
startRemoteWorkerSystem();
if (args.length == 0 || args[0].equals("Creation"))
startRemoteCreationSystem();
}
public static void startRemoteWorkerSystem() {
ActorSystem.create("CalculatorWorkerSystem",
ConfigFactory.load(("calculator")));
System.out.println("Started CalculatorWorkerSystem");
}
public static void startRemoteCreationSystem() {
final ActorSystem system = ActorSystem.create("CreationSystem",
ConfigFactory.load("remotecreation"));
final ActorRef actor = system.actorOf(Props.create(CreationActor.class),
"creationActor");
System.out.println("Started CreationSystem");
final Random r = new Random();
system.scheduler().schedule(Duration.create(1, SECONDS),
Duration.create(1, SECONDS), new Runnable() {
@Override
public void run() {
if (r.nextInt(100) % 2 == 0) {
actor.tell(new Op.Multiply(r.nextInt(100), r.nextInt(100)), null);
} else {
actor.tell(new Op.Divide(r.nextInt(10000), r.nextInt(99) + 1),
null);
}
}
}, system.dispatcher());
}
}</span>
源码运行的结果为:
Started CalculatorWorkerSystem
Started CreationSystem
Calculating 4915.0 / 63
Div result: 4915 / 63 = 78.02
Calculating 1409.0 / 15
Div result: 1409 / 15 = 93.93
Calculating 99 * 64
Mul result: 99 * 64 = 6336
4、源码分析
4.1,我们先看一下序列图,看看是如何调用的。
4.2 一些关键内容的说明
1、只能创建一个WorkerSystem
ActorSystem.create("CalculatorWorkerSystem", ConfigFactory.load(("calculator")));
2、 只能创建一个ActorSystem
final ActorSystem system = ActorSystem.create("CreationSystem", ConfigFactory.load("remotecreation"));
3、创建Actor
final ActorRef actor = system.actorOf(Props.create(CreationActor.class), "creationActor");
4、发送消息给这个Actor
actor.tell(new Op.Multiply(r.nextInt(100), r.nextInt(100)), null);
5、 Actor 返回消息给上层调用的Actor
getSender().tell(result, getSelf());