Classic Actor
AKKa2.6.0版本提供了Akka Typed的稳定API,开始主推Typed API, Akka Typed模块在2.4版本提出,其模块提供了在完整的类型系统支持下构建Actor交互的新方法(a new way of formulating Actor interactions with full type-system support)[1]。在2.6.0之后, Akka Classic是指原先Actor API,虽然AKKa推荐使用新的Actor API,但是2.6.0依然完全支持Classic API,因此现有程序继续使用Classic Actor API是完全没有问题。[2]
Akka的Actor模型
Actor模型为编写并发和分布式系统提供了更高层次的抽象。它减轻了开发人员必须处理显式锁和线程管理的负担,能够避免在自己的代码中写同步和锁,使编写正确的并发和并行系统变得更加容易。actor是Carl Hewitt在1973年的论文中定义的,但由于Erlang语言的使用而得到推广,例如在Ericsson中就成功地用于构建高度并发和可靠的电信系统。
Definition a Java classic Actor class
Actor类是通过继承AbstractActor类来实现的,需要重写createReceive方法,在createReceive方法中定义该actor可以处理哪些消息以及如何处理消息。
import akka.actor.AbstractActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;
public class RequestActor1 extends AbstractActor {
protected final LoggingAdapter log = Logging.getLogger(context().system(),this);
@Override
public Receive createReceive() {
return receiveBuilder()
.match(String.class,message -> { log.info(message);})
.matchAny(message -> {log.info("Any match: "+message);})
.build();
}
}
简要描述处理消息的API,receiveBuilder()提供需要匹配输入消息的响应方法,如match,matchEquals,matchAny..,最后调用build()生成需要返回的PartialFunction。
- match(class,function):处理任何匹配的class类型的消息,响应逻辑写在第二个参数function
- match(class,predicate,function):处理匹配class类型,且predicate条件函数为真的消息
- matchEquals(object,function):处理object相等的消息,可以是字符串,数字等
- matchAny(function):处理至此还未被匹配的消息,通常用来处理异常消息
match函数是从上至下进行模式匹配的,所以matAny()放于最后用于返回错误信息或者对未匹配消息进行特殊处理(日记记录,转发)
测试:
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.testkit.TestActorRef;
import org.junit.jupiter.api.Test;
class RequestActor1Test {
ActorSystem actorSystem = ActorSystem.create();
@Test
public void test() {
TestActorRef<RequestActor1> actorRef = TestActorRef.create(actorSystem, Props.create(RequestActor1.class));
actorRef.tell("Hello world!", ActorRef.noSender());
}
}
Messages and immutability
Actor的消息可以任何类型,但必须是不可改变的。AKKA的文档中强调“AKKA不能强制消息是不可变,所以消息不可变是一个约定”。在Java中,即在Actor的消息加上final修饰
public class RequestActor4 extends AbstractActor {
protected final String name;
protected final LoggingAdapter log = Logging.getLogger(context().system(),this);
protected final Map<String, Object> map = new HashMap<>();
public RequestActor4(String name) {
this.name = name;
}
//......
}