The actor traits Reactor, ReplyReactor, and Actor | Contents | Index |
Reactor
is the super trait of all actor traits. Extending this
trait allows defining actors with basic capabilities to send and
receive messages.
The behavior of a Reactor
is defined by implementing its
act
method. The act
method is executed once the
Reactor
is started by invoking start
, which also returns
the Reactor
. The start
method is idempotent which
means that invoking it on an actor that has already been started has
no effect.
The Reactor
trait has a type parameter Msg
which
indicates the type of messages that the actor can receive.
Invoking the Reactor
's !
method sends a message to the
receiver. Sending a message using !
is asynchronous which means
that the sending actor does not wait until the message is received;
its execution continues immediately. For example, a ! msg
sends
msg
to a
. All actors have a mailbox which buffers
incoming messages until they are processed.
The Reactor
trait also defines a forward
method. This
method is inherited from OutputChannel
. It has the same effect
as the !
method. Subtraits of Reactor
, in particular the
ReplyReactor
trait, override this method to enable implicit
reply destinations (see below).
A Reactor
receives messages using the react
method.1 react
expects an
argument of type PartialFunction[Msg, Unit]
which defines how
messages of type Msg
are handled once they arrive in the
actor's mailbox. In the following example, the current actor waits to
receive the string ""Hello", and then prints a greeting:
react { case "Hello" => println("Hi there") }
Invoking react
never returns. Therefore, any code that should
run after a message has been received must be contained inside the
partial function that is passed to react
. For example, two
messages can be received in sequence by nesting two invocations of
react
:
react { case Get(from) => react { case Put(x) => from ! x } }
The Reactor
trait also provides control structures (see
*) which simplify programming with
react
.
The execution of a Reactor
terminates when the body of its
act
method has run to completion. A Reactor
can also
terminate itself explicitly using the exit
method. The return
type of exit
is Nothing
, because exit
always
throws an exception. This exception is only used internally, and
should never be caught.
A terminated Reactor
can be restarted by invoking its
restart
method. Invoking restart
on a Reactor
that has not terminated, yet, throws an
IllegalStateException
. Restarting a terminated actor causes its
act
method to be rerun.
Reactor
defines a method getState
which returns the
actor's current execution state as a member of the Actor.State
enumeration. An actor that has not been started, yet, is in state
Actor.State.New
. An actor that can run without waiting for a
message is in state Actor.State.Runnable
. An actor that is
suspended, waiting for a message is in state
Actor.State.Suspended
. A terminated actor is in state
Actor.State.Terminated
.
The exceptionHandler
member allows defining an exception
handler that is enabled throughout the entire lifetime of a
Reactor
:
def exceptionHandler: PartialFunction[Exception, Unit]
exceptionHandler
returns a partial function which is used to
handle exceptions that are not otherwise handled: whenever an
exception propagates out of the body of a Reactor
's act
method, the partial function is applied to that exception, allowing
the actor to run clean-up code before it terminates. Note that the
visibility of exceptionHandler
is protected
.
Handling exceptions using exceptionHandler
works well together
with the control structures for programming with react
(see
*). Whenever an exception has been handled
using the partial function returned by exceptionHandler
,
execution continues with the current continuation closure. Example:
loop { react { case Msg(data) => if (cond) // process data else throw new Exception("cannot process data") } }
Assuming that the Reactor
overrides exceptionHandler
,
after an exception thrown inside the body of react
is handled,
execution continues with the next loop iteration.
The ReplyReactor
trait extends Reactor[Any]
and adds or
overrides the following methods:
!
method is overridden to obtain a reference to the
current actor (the sender); together with the actual message, the
sender reference is transferred to the mailbox of the receiving
actor. The receiver has access to the sender of a message through
its sender
method (see below).
forward
method is overridden to obtain a reference to
the sender of the message that is currently being
processed. Together with the actual message, this reference is
transferred as the sender of the current message. As a consequence,
forward
allows forwarding messages on behalf of actors
different from the current actor.
sender
method returns the sender of the message
that is currently being processed. Given the fact that a message
might have been forwarded, sender
may not return the actor
that actually sent the message.
reply
method sends a message back to the sender
of the last message. reply
is also used to reply to a
synchronous message send or a message send with future (see below).
!?
methods provide synchronous message
sends. Invoking !?
causes the sending actor to wait until
a response is received which is then returned. There are two
overloaded variants. The two-parameter variant takes in addition a
timeout argument (in milliseconds), and its return type is
Option[Any]
instead of Any
. If the sender does not
receive a response within the specified timeout period, !?
returns None
, otherwise it returns the response wrapped in
Some
.
!!
methods are similar to synchronous message
sends in that they allow transferring a response from the
receiver. However, instead of blocking the sending actor until a
response is received, they return Future
instances. A
Future
can
be used to retrieve the response of the receiver once it is
available; it can also be used to find out whether the response is
already available without blocking the sender (). There are two
overloaded variants. The two-parameter variant takes in addition an
argument of type PartialFunction[Any, A]
. This partial
function is used for post-processing the receiver's
response. Essentially, !!
returns a future which applies the
partial function to the response once it is received. The result of
the future is the result of this post-processing.
reactWithin
method allows receiving messages
within a given period of time. Compared to react
it takes an
additional parameter msec
which indicates the time period in
milliseconds until the special TIMEOUT
pattern matches
(TIMEOUT
is a case object in package
scala.actors
). Example:
reactWithin(2000) { case Answer(text) => // process text case TIMEOUT => println("no answer within 2 seconds") }
The reactWithin
method also allows non-blocking access to the
mailbox. When specifying a time period of 0 milliseconds, the mailbox
is first scanned to find a matching message. If there is no matching
message after the first scan, the TIMEOUT
pattern matches. For
example, this enables receiving certain messages with a higher
priority than others:
reactWithin(0) { case HighPriorityMsg => // ... case TIMEOUT => react { case LowPriorityMsg => // ... } }
In the above example, the actor first processes the next
HighPriorityMsg
, even if there is a LowPriorityMsg
that
arrived earlier in its mailbox. The actor only processes a
LowPriorityMsg
first if there is no
HighPriorityMsg
in its mailbox.
In addition, ReplyReactor
adds the
Actor.State.TimedSuspended
execution state. A suspended actor,
waiting to receive a message using reactWithin
is in state
Actor.State.TimedSuspended
.
The Actor
trait extends ReplyReactor
and adds or
overrides the following members:
receive
method behaves like react
except
that it may return a result. This is reflected in its type, which is
polymorphic in its result:
def receive[R](f: PartialFunction[Any, R]): R
However, using receive
makes the actor more heavyweight,
since receive
blocks the underlying thread while the actor is
suspended waiting for a message. The blocked thread is unavailable
to execute other actors until the invocation of receive
returns.
link
and unlink
methods allow an actor
to link and unlink itself to and from another actor,
respectively. Linking can be used for monitoring and reacting to the
termination of another actor. In particular, linking affects the
behavior of invoking exit
as explained in the API
documentation of the
Actor
trait.
trapExit
member allows reacting to the termination of
linked actors independently of the exit reason (that is, it does not
matter whether the exit reason is 'normal
or not). If an
actor's trapExit
member is set to true
, this actor
will never terminate because of linked actors. Instead, whenever one
of its linked actors terminates it will receive a message of type
Exit
. The Exit
case class has two members: from
refers to the actor that terminated; reason
refers to the
exit reason.
When terminating the execution of an actor, the exit reason can be set
explicitly by invoking the following variant of exit
:
def exit(reason: AnyRef): Nothing
An actor that terminates with an exit reason different from the symbol
'normal
propagates its exit reason to all actors linked to
it. If an actor terminates because of an uncaught exception, its exit
reason is an instance of the
UncaughtException
case class.
The Actor
trait adds two new execution states. An actor
waiting to receive a message using receive
is in state
Actor.State.Blocked
. An actor waiting to receive a message
using receiveWithin
is in state
Actor.State.TimedBlocked
.
The actor traits Reactor, ReplyReactor, and Actor | Contents | Index |