The Actor Model provides a higher level of abstraction for writing concurrent and distributed systems. It alleviates the developer from having to deal with explicit locking and thread management, making it easier to write correct concurrent and parallel systems. Actors were defined in the 1973 paper by Carl Hewitt but have been popularized by the Erlang language, and used for example at Ericsson with great success to build highly concurrent and reliable telecom systems.

Creating an Actor is done using the ‘akka.actor.Actors.actorOf’ factory method. This method returns a reference to the UntypedActor’s ActorRef. This ‘ActorRef’ is an immutable serializable reference that you should use to communicate with the actor, send messages, link to it etc. This reference also functions as the context for the actor and holds run-time type information such as sender of the last message,

The call to ‘actorOf’ returns an instance of ‘ActorRef’. This is a handle to the ‘UntypedActor’ instance which you can use to interact with the Actor, like send messages to it etc. more on this shortly. The ‘ActorRef’ is immutable and has a one to one relationship with the Actor it represents. The ‘ActorRef’ is also serializable and network-aware. This means that you can serialize it, send it over the wire and use it on a remote host and it will still be representing the same Actor on the original node, across the network.

If your UntypedActor has a constructor that takes parameters then you can’t create it using ‘actorOf(clazz)’. Instead you can use a variant of ‘actorOf’ that takes an instance of an ‘UntypedActorFactory’ in which you can create the Actor in any way you like. If you use this method then you to make sure that no one can get a reference to the actor instance. If they can get a reference it then they can touch state directly in bypass the whole actor dispatching mechanism and create race conditions which can lead to corrupt data.

The UntypedActor base class contains almost no member fields or methods to invoke. It only has the ‘onReceive(Object message)’ method, which is defining the Actor’s message handler, and some life-cycle callbacks that you can choose to implement:
## preStart
## postStop
## preRestart
## postRestart

Most of the API is in the UnypedActorRef a reference for the actor. This reference is available in the ‘getContext()’ method in the UntypedActor (or you can use its alias, the ‘context()’ method, if you prefer. Here, for example, you find methods to reply to messages, send yourself messages, define timeouts, fault tolerance etc., start and stop etc.

Each ActorRef has two methods:
* getContext().getUuid();
* getContext().getId();

The difference is that the ‘uuid’ is generated by the runtime, guaranteed to be unique and can’t be modified. While the ‘id’ can be set by the user (using ‘getContext().setId(...)’, and defaults to Actor class name. You can retrieve Actors by both UUID and ID using the ‘ActorRegistry’, see the section further down for details.

Messages are sent to an Actor through one of the ‘send’ methods.
* ‘sendOneWay’ means “fire-and-forget”, e.g. send a message asynchronously and return immediately.
* ‘sendRequestReply’ means “send-and-reply-eventually”, e.g. send a message asynchronously and wait for a reply through a Future. Here you can specify a timeout. Using timeouts is very important. If no timeout is specified then the actor’s default timeout (set by the ‘getContext().setTimeout(..)’ method in the ‘ActorRef’) is used. This method throws an ‘ActorTimeoutException’ if the call timed out.
* ‘sendRequestReplyFuture’ sends a message asynchronously and returns a ‘Future’.

In all these methods you have the option of passing along your ‘ActorRef’ context variable. Make it a practice of doing so because it will allow the receiver actors to be able to respond to your message, since the sender reference is sent along with the message.

This is the preferred way of sending messages. No blocking waiting for a message. Give best concurrency and scalability characteristics.

actor.sendOneWay("Hello");

Or with the sender reference passed along:

actor.sendOneWay("Hello",getContext());

If invoked from within an Actor, then the sending actor reference will be implicitly passed along with the message and available to the receiving Actor in its ‘getContext().getSender();’ method. He can use this to reply to the original sender or use the ‘getContext().reply(message);’ method.

If invoked from an instance that is not an Actor there will be no implicit sender passed along the message and you will get an ‘IllegalStateException’ if you call ‘getContext().reply(..)’.

You can forward a message from one actor to another. This means that the original sender address/reference is maintained even though the message is going through a ‘mediator’. This can be useful when writing actors that work as routers, load-balancers, replicators etc. You need to pass along your ActorRef context variable as well.

If you want to have a handle to an object to whom you can reply to the message, you can use the Channel abstraction.
Simply call getContext().channel() and then you can forward that to others, store it away or otherwise until you want to reply,
which you do by Channel.sendOneWay(msg)

publicvoidonReceive(Objectmessage)throwsException{if(messageinstanceofString){Stringmsg=(String)message;if(msg.equals("Hello")&&getContext().getSenderFuture().isDefined()){// Reply to original sender of message using the channelgetContext().channel().sendOneWay(msg+" from "+getContext().getUuid());}}}

We recommend that you as first choice use the channel abstraction instead of the other ways described in the following sections.

If you want to send a message back to the original sender of the message you just received then you can use the ‘getContext().replyUnsafe(..)’ method.

publicvoidonReceive(Objectmessage)throwsException{if(messageinstanceofString){Stringmsg=(String)message;if(msg.equals("Hello")){// Reply to original sender of message using the 'replyUnsafe' methodgetContext().replyUnsafe(msg+" from "+getContext().getUuid());}}}

In this case we will a reply back to the Actor that sent the message.

The ‘replyUnsafe’ method throws an ‘IllegalStateException’ if unable to determine what to reply to, e.g. the sender has not been passed along with the message when invoking one of ‘send*’ methods. You can also use the more forgiving ‘replySafe’ method which returns ‘true’ if reply was sent, and ‘false’ if unable to determine what to reply to.

publicvoidonReceive(Objectmessage)throwsException{if(messageinstanceofString){Stringmsg=(String)message;if(msg.equals("Hello")){// Reply to original sender of message using the 'replyUnsafe' methodif(getContext().replySafe(msg+" from "+getContext().getUuid()))...// successelse...// handle failure}}}

If the sender reference (the sender’s ‘ActorRef’) is passed into one of the ‘send*’ methods it will be implicitly passed along together with the message and will be available in the ‘Option<ActorRef> getSender()’ method on the ‘ActorRef. This means that you can use this field to send a message back to the sender.

On this ‘Option’ you can invoke ‘boolean isDefined()’ or ‘boolean isEmpty()’ to check if the sender is available or not, and if it is call ‘get()’ to get the reference. It’s important to know that ‘getSender().get()’ will throw an exception if there is no sender in scope. The same pattern holds for using the ‘getSenderFuture()’ in the section below.

publicvoidonReceive(Objectmessage)throwsException{if(messageinstanceofString){Stringmsg=(String)message;if(msg.equals("Hello")){// Reply to original sender of message using the sender reference// also passing along my own reference (the context)if(getContext().getSender().isDefined)getContext().getSender().get().sendOneWay(msg+" from "+getContext().getUuid(),getContext());}}}

If a message was sent with the ‘sendRequestReply’ or ‘sendRequestReplyFuture’ methods, which both implements request-reply semantics using Future’s, then you either have the option of replying using the ‘reply’ method as above. This method will then resolve the Future. But you can also get a reference to the Future directly and resolve it yourself or if you would like to store it away to resolve it later, or pass it on to some other Actor to resolve it.

The reference to the Future resides in the ‘ActorRef’ instance and can be retrieved using ‘Option<CompletableFuture> getSenderFuture()’.

CompletableFuture is a future with methods for ‘completing the future:
* completeWithResult(..)
* completeWithException(..)

Here is an example of how it can be used:

publicvoidonReceive(Objectmessage)throwsException{if(messageinstanceofString){Stringmsg=(String)message;if(msg.equals("Hello")&&getContext().getSenderFuture().isDefined()){// Reply to original sender of message using the sender future referencegetContext().getSenderFuture().get().completeWithResult(msg+" from "+getContext().getUuid());}}}

getContext().getSender() is a reference to the actor you can reply to, if it exists

getContext().getSenderFuture() is a reference to the future you can reply to, if it exists

getContext().channel() is a reference providing an abstraction to either self.sender or self.senderFuture if one is set, providing a single reference to store and reply to (the reference equivalent to the ‘reply(...)’ method).

getContext().getSender() and getContext().getSenderFuture() will never be set at the same time, as there can only be one reference to accept a reply.

You can also send an actor the akka.actor.PoisonPill message, which will stop the actor when the message is processed.
If the sender is a Future, the Future will be completed with an akka.actor.ActorKilledException(“PoisonPill”)