Java High Concurrency Programming Learning--7.9 Question Mode: Future in Actor

Posted by JAB Creations on Thu, 11 Jul 2019 19:27:28 +0200

Because Actors communicate through asynchronous messages.When a message is sent to an Actor, it is usually only possible to wait for the Actor to return.Unlike synchronous methods, after sending an asynchronous message, the Actor receiving the message may not have time to process your message at all, and the caller has already returned.
This pattern is very similar to the Future pattern mentioned earlier.The difference is that in traditional asynchronous calls, function calls are made, but here a message is sent.
public class AskMain {
	public static void main(String[] args) throws Exception {
		ActorSystem system = ActorSystem.create("askdemo", ConfigFactory.load("samplehello.conf"));
		ActorRef worker = system.actorOf(Props.create(Worker.class), "worker");
		ActorRef printer = system.actorOf(Props.create(Printer.class), "printer");
		system.actorOf(Props.create(WatchActor.class, worker), "watcher");
		
		//Waiting for future to return
		Future<Object> f = Patterns.ask(worker, 5, 1500);
		int re = (int)Await.result(f, Duration.create(6, TimeUnit.SECONDS));
		System.out.println("return:" + re);
		
		//Direct to other Actor s, pipe won't wait
		f = Patterns.ask(worker, 6, 1500);
		Patterns.pipe(f, system.dispatcher()).to(printer);
		worker.tell(PoisonPill.getInstance(), ActorRef.noSender());
	}
}
The code above gives two examples of using Future in an Actor interaction.
The code uses the ask() method to send a message to the worker with a message content of 5, which means the worker receives an Integer message with a value of 5.When the worker receives the message, it can calculate and process it and return the result to the sender.Of course, this process will take a while.
The method ask() does not wait for the worker to process, but immediately returns a Future object.In the code, use the Await method to wait for the worker to return, then print the return.
In this method, an asynchronous call is indirectly converted to a synchronous blocking call.Although easy to understand, there are some occasions when performance problems may occur.Another more effective method is to use the pipe() function.
The code uses ask() to ask the worker again and pass the value 6 to the worker.Instead of waiting, use pipe () to redirect the Future to another Actor called printer.The pipe() function does not block the program and returns immediately.
This printer is implemented simply by outputting the resulting data:
@Override
public void onReceive(Object msg) throws Exception {
	if(msg instanceof Integer) {
		System.out.println("Printer:" + msg);
	}
		
	if(msg == Msg.DONE) {
		log.info("Stop working");
	}
	if(msg == Msg.CLOSE) {
		log.info("I will shutdown");
		getSender().tell(Msg.CLOSE, getSelf());
		getContext().stop(getSelf());
	} else {
		unhandled(msg);
	}
}
The above code is the implementation of the Printer Actor, which gets the output of the worker through the pipe() method and prints it to the console.
Worker Actor receives an integer, calculates its square, and returns it as follows:
@Override
public void onReceive(Object msg) throws Exception {
	if(msg instanceof Integer) {
		int i = (Integer)msg;
		try {
			Thread.sleep(1000);
		} catch (Exception e) {
			// TODO: handle exception
		}
		getSender().tell(i*i, getSelf());
	}
	if(msg == Msg.DONE) {
		log.info("Stop working");
	}
	if(msg == Msg.CLOSE) {
		log.info("I will shutdown");
		getSender().tell(Msg.CLOSE, getSelf());
		getContext().stop(getSelf());
	} else {
		unhandled(msg);
	}
}
The code above simulates a time-consuming call to more clearly illustrate the purpose of the ask() and pipe() methods.The worker calculates the square of the given value and "tells" the requester.