向一个actor发送消息,除使用tell,还可以使用ask进行请求.
tell异步发送消息:它用于异步发送消息。它不会等待并阻止线程发送消息;提供了最佳的并发性和可伸缩性。
Ask用于异步发送消息:它返回一个Future, 表示可能的答复。如果Actor没有回复并完成未来, 它将在超时期限后过期。超时时间过后, 它将引发TimeoutException。
forward为消息转发:其作用主要是能保持最开发发送的actor,如A发送消息M至B,B中forward至C,则C中获取消息的sender仍然为A
下面介绍下ask的使用:
辅助类
消息
package com.zte.sunquan.demo.actor.ask;
import java.io.Serializable;
/**
* Created by on 2017/10/10.
*/
public class Message implements Serializable{
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Message{");
sb.append("id=").append(id);
sb.append('}');
return sb.toString();
}
}
打印
package com.zte.sunquan.demo.actor.ask;
import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.actor.ReceiveTimeout;
import java.time.Instant;
/**
* Created by on 2017/9/19.
*/
public class PrintActor extends AbstractActor {
public static Props props(){
return Props.create(PrintActor.class);
}
@Override
public Receive createReceive() {
return receiveBuilder().match(String.class,
s -> {
System.out.println(s + ":" + Instant.now());
})
.match(ReceiveTimeout.class, t ->
System.out.println("ReceiveTimeout")
).match(Throwable.class, t ->
System.out.println("Throwable")
// breaker.fail()
)
.build();
}
}
处理actor
package com.zte.sunquan.demo.actor.ask;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.DeadLetterActorRef;
import akka.actor.Props;
import akka.dispatch.Futures;
import akka.dispatch.Mapper;
import akka.dispatch.OnComplete;
import akka.pattern.Patterns;
import akka.util.Timeout;
import com.google.common.collect.Lists;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import static akka.pattern.Patterns.pipe;
/**
* Created by sunquan on 2017/10/10.
*/
public class ProcessActor extends AbstractActor {
final Timeout timeout = new Timeout(Duration.create(5, TimeUnit.SECONDS));
private ActorRef sub1Actor = getContext().actorOf(ProcessSub1Actor.props());
private ActorRef sub2Actor = getContext().actorOf(ProcessSub2Actor.props());
private ActorRef printActor = getContext().actorOf(PrintActor.props());
public static Props props() {
return Props.create(ProcessActor.class);
}
@Override
public Receive createReceive() {
return receiveBuilder().match(String.class, p -> {
System.out.println("ProcessActor receive:" + p);
// Thread.sleep(6000);
getSender().tell("process success", getSelf());
}).match(Message.class, p -> {
//多actor参与计算-->最后合并结果
Future<Object> process1 = Patterns.ask(sub1Actor, p, timeout);
Future<Object> process2 = Patterns.ask(sub2Actor, p, timeout);
//主要是为了控制返回结果顺序
final Future<Iterable<Object>> aggregate = Futures.sequence(
Lists.newArrayList(process1, process2),
getContext().system().dispatcher());
//可使用get直接获取结果,这里使用map对结果进行转换
final Future<String> aggResult = aggregate.map(
new Mapper<Iterable<Object>, String>() {
public String apply(Iterable<Object> coll) {
final Iterator<Object> it = coll.iterator();
final String process1Result = (String) it.next();
final String process2Result = (String) it.next();
return process1Result + "---" + process2Result;
}
}, getContext().system().dispatcher());
// aggregated result is piped to another actor
if (getSender() == null || getSender() == ActorRef.noSender()
|| getSender() instanceof DeadLetterActorRef) {
aggResult.onComplete(new OnComplete<String>() {
@Override
public void onComplete(Throwable throwable, String s) throws Throwable {
if (throwable == null&&aggResult.isCompleted())
System.out.println("Result:" + aggResult.value());
else
System.out.println(throwable);
}
}, getContext().system().dispatcher());
} else {
// pipe(aggResult, getContext().system().dispatcher()).to(
// printActor);
pipe(aggResult, getContext().system().dispatcher()).to(
getSender());
}
})
.build();
}
}
package com.zte.sunquan.demo.actor.ask;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Props;
import java.util.concurrent.TimeUnit;
/**
* Created by x on 2017/9/18.
*/
public class ProcessSub1Actor extends AbstractActor {
public static Props props() {
return Props.create(ProcessSub1Actor.class);
}
@Override
public Receive createReceive() {
return receiveBuilder().match(Message.class,(content)->{
System.out.println("ProcessSub1Actor process:"+content);
// TimeUnit.SECONDS.sleep(4);
getSender().tell("ProcessSub1Actor result:"+content, ActorRef.noSender());
}).build();
}
}
package com.zte.sunquan.demo.actor.ask;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Props;
import java.util.concurrent.TimeUnit;
/**
* Created by x on 2017/9/18.
*/
public class ProcessSub2Actor extends AbstractActor {
public static Props props() {
return Props.create(ProcessSub2Actor.class);
}
@Override
public Receive createReceive() {
return receiveBuilder().match(Message.class,(content)->{
System.out.println("ProcessSub2Actor process:"+content);
// TimeUnit.SECONDS.sleep(4);
getSender().tell("ProcessSub2Actor result:"+content, ActorRef.noSender());
}).build();
}
}
上面代码关键处,都包含了注释
测试用例:
package com.zte.sunquan.demo.actor.ask;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.dispatch.Mapper;
import akka.dispatch.OnComplete;
import akka.pattern.Patterns;
import akka.util.Timeout;
import org.junit.Test;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Created by x on 2017/10/10.
*/
public class ProcessActorTest {
@Test
public void startMessageTest() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
Timeout t = new Timeout(Duration.create(5, TimeUnit.SECONDS));
ActorSystem system = ActorSystem.create();
ActorRef myActor = system.actorOf(ProcessActor.props());
ActorRef printActor = system.actorOf(PrintActor.props());
// myActor.tell(new Message(), printActor);
myActor.tell(new Message(), ActorRef.noSender());
latch.await();
}
@Test
public void startTest() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
Timeout t = new Timeout(Duration.create(5, TimeUnit.SECONDS));
ActorSystem system = ActorSystem.create();
ActorRef myActor = system.actorOf(ProcessActor.props());
//使用ask发送消息,actor处理完,必须有返回(超时时间5秒)
Future<Object> ask = Patterns.ask(myActor, "Hello,world", t);
ask.onComplete(new OnComplete<Object>() {
@Override
public void onComplete(Throwable throwable, Object o) throws Throwable {
if (throwable != null) {
//如果处理延迟大于ask参数
//akka.pattern.AskTimeoutException:
// Ask timed out on [Actor[akka://default/user/$a#2060184193]] after [5000 ms].
// Sender[null] sent message of type "java.lang.String".
// 从上一句话判断,处理函数一定要将string传递
System.out.println(throwable);
} else {
System.out.println(o);
}
}
}, system.dispatcher());
//对结果进行取map (无法处理异常)
ask.map(new Mapper<Object, Object>() {
@Override
public Object apply(Object o) {
System.out.println("apply ask:" + o);
return "end";
}
}, system.dispatcher());
// System.out.println(ask.value().get().get());
latch.await();
}
}
在接收到Message后,通过ask分别发送消息到sub1和sub2,然后处理返回结果,在sender存在情况下pipe,i不存在则注释回调函数,在回调中处理结果