Typesafe Activator

Hello Akka (Java 8)

Hello Akka (Java 8)

typesafehub
Source
March 26, 2014
akka java java8

This simple Akka application uses Java 8 and Lambdas for a concise Reactive programming model with Actors.

How to get "Hello Akka (Java 8)" on your computer

There are several ways to get this template.

Option 1: Choose hello-akka-java8 in the Typesafe Activator UI.

Already have Typesafe Activator (get it here)? Launch the UI then search for hello-akka-java8 in the list of templates.

Option 2: Download the hello-akka-java8 project as a zip archive

If you haven't installed Activator, you can get the code by downloading the template bundle for hello-akka-java8.

  1. Download the Template Bundle for "Hello Akka (Java 8)"
  2. Extract the downloaded zip file to your system
  3. The bundle includes a small bootstrap script that can start Activator. To start Typesafe Activator's UI:

    In your File Explorer, navigate into the directory that the template was extracted to, right-click on the file named "activator.bat", then select "Open", and if prompted with a warning, click to continue:

    Or from a command line:

     C:\Users\typesafe\hello-akka-java8> activator ui 
    This will start Typesafe Activator and open this template in your browser.

Option 3: Create a hello-akka-java8 project from the command line

If you have Typesafe Activator, use its command line mode to create a new project from this template. Type activator new PROJECTNAME hello-akka-java8 on the command line.

Option 4: View the template source

The creator of this template maintains it at https://github.com/typesafehub/activator-hello-akka-java8#master.

Option 5: Preview the tutorial below

We've included the text of this template's tutorial below, but it may work better if you view it inside Activator on your computer. Activator tutorials are often designed to be interactive.

Preview the tutorial

You've just created a simple Akka application! Now lets explore the code and make some changes.

In short, Akka is a toolkit and runtime for building highly concurrent, distributed, and fault-tolerant event-driven applications on the JVM. Akka can be used with both Java and Scala. One of the most powerful features of Akka is its Actor Model of concurrency, which you will learn more about in this tutorial.

Source code

The HelloAkka.java file is the whole application in this example.

The sample in this tutorial is pretty simple; it consists of a Greeter Actor who holds onto the latest defined greeting string and can respond to two actions; set a new greeting string and return the latest greeting string.

Next let's get started.

Define our Messages

An Actor does not have a public API in terms of methods that you can invoke. Instead its public API is defined through messages that the actor handles. Messages can be of arbitrary type (any subtype of Object in Java). This means that we can send boxed primitive values (such as String, Integer, Boolean etc.) as messages or plain data structures like arrays and collection types. However, since the messages are the Actor's public API, you should define messages with good names and rich semantic and domain specific meaning, even if it's just wrapping your data type. This will make it easier to use, understand and debug actor-based systems.

Now we want to define three different messages;

  • WhoToGreet redefines the new greeting
  • Greet asks the Actor for latest greeting
  • Greeting returns the latest greeting

Let's start by defining the messages (we are putting them inside an outer HelloAkka class, containing our full sample). It is very important that the messages we create are immutable (meaning that they cannot be changed), if not we run the risk of accidentally sharing state between two different Actors which will violate the Actor Model. In this sample we will not use any remoting, but it is a good practice to always mark your messages as Serializable since then you will not run in to any runtime issues if you decide to scale out (on to multiple nodes) with Akka but forget to go back and reimplement your messages.


public static class Greet implements Serializable {}

public static class WhoToGreet implements Serializable {
    public final String who;
    public WhoToGreet(String who) {
        this.who = who;
    }
}

public static class Greeting implements Serializable {
    public final String message;
    public Greeting(String message) {
        this.message = message;
    }
}
        

Define our Actor

The Actor is the unit of execution in Akka. Actors are object-oriented in the sense that they encapsulate state and behavior, but they have much stronger isolation than regular objects in Java. The Actor model prevents sharing state between Actors and the only way to observe another actor's state is by sending it a message asking for it. Actors are extremely lightweight, they are only constrained by memory of which they consume only a few hundred bytes each — this means you can easily create millions of concurrent Actors in a single application. Their strong isolation principles together with the event-driven model (that we will talk about later on) and location transparency makes it easy to solve hard concurrency and scalability problems in an intuitive way.

To create an Actor that uses Lambdas define a class that extends AbstractActor and implement the receive() method. It is in the receive() method that you define the behavior; how the Actor should react to the different messages it receives. An Actor can have — and often has — state. Accessing or mutating the internal state of an Actor is fully thread safe since protected by the Actor model.

So, let's now create a Greeter Actor with a single variable greeting as its state, holding on to the latest defined greeting, and in its receive() method let's add the behavior for how it should react upon receiving the WhoToGreet and the Greet messages.

Let's start by creating our Actor in Java (you can find the code in the HelloAkka.java file):


public static class Greeter extends AbstractActor {
    String greeting = "";

    @Override public PartialFunction>Object, BoxedUnit< receive() {
        return ReceiveBuilder.
            match(WhoToGreet.class, message -> greeting = "hello, " + message.who).
            match(Greet.class, message -> sender().tell(new Greeting(greeting), self())).
            build();
    }
}
        

Actors like this one are "untyped" in the sense that the type of message received is not restricted—it is Object as shown above. There are also typed actors, but we will not concern ourselves with those now, the normal actors are the untyped ones.

Don't worry about the sender(), tell(..) and self() API calls, we will get to that soon when we talk about sending and replying to messages.

Create our Actor

So far we have defined our Actor and its messages. Now let's create an instance of this actor. In Akka you can't create an instance of an Actor the regular way using new, instead you create it using a factory. What is returned from this factory is not an instance of the Actor itself but an ActorRef pointing to our actor instance.

This level of indirection adds a lot of power and flexibility. It enables for example location transparency meaning that the ActorRef can, while retaining the same semantics, represent an instance of the running actor in-process or on a remote machine. I.e. location doesn't matter. This also means that the runtime can if needed optimize the system by changing an actor's location or the application's topology while it is running. Another thing that this level of indirection enables is the "let it crash" model of failure management in which the system can heal itself by crashing and restarting faulty actors.

This factory in Akka is the ActorSystem and is to some extent similar to Spring's BeanFactory in that it also acts as a container for your Actors, managing their life-cycles etc. You create an Actor through the actorOf factory method. This method takes a configuration object called Props and a name. Actor (and ActorSystem) names are important in Akka, you use them for example when looking Actors up as well as when you configure them in the configuration file, so you should take your time giving your Actors good names.

This is the code that we have to write in Java:


final ActorSystem system = ActorSystem.create("helloakka");
final ActorRef greeter = system.actorOf(Props.create(Greeter.class), "greeter");
        

Now we have a running instance of a Greeter actor. Next we will learn how to communicate with it.

Tell the Actor (to do something)

All communication with Actors is done through asynchronous message passing. This is what makes Actors reactive and event driven. An Actor doesn't do anything unless it's been told to do something, and you tell it to do something by sending the message. Sending a message asynchronously means that the sender does not stick around waiting for the message to be processed by the recipient actor. Instead the Actor hands the message off by putting it on the recipient's mailbox and is then free to do something more important than waiting for the recipient to react on the message. The actor's mailbox is essentially a message queue and has ordering semantics, this guarantees that the ordering of multiple messages sent from the same Actor is preserved, while they can be interleaved with the messages sent by another actor.

You might be wondering what the Actor is doing when it is not processing messages, i.e. doing actual work? It is in a suspended state in which it does not consume any resources apart from memory.

You tell an Actor to do something by passing in a message into the tell method on the ActorRef. This method puts the message on the actor's mailbox and then returns immediately.

greeter.tell(new WhoToGreet("akka"), ActorRef.noSender());

Replying to an Actor

The 'self' reference

Sometimes the the communication pattern is not just a one-way style of communication but instead lends itself towards request-reply. One explicit way of doing that is by adding a reference of yourself as part of the message so the receiver can use that reference to send a reply back to you. This is such a common scenario that it is directly supported by Akka; for every message you send you have the option of passing along the sender reference (the Actor's ActorRef). If you are sending a message from within an Actor then you have access to your own ActorRef through self reference, please note that you should never use this. You can access the self reference through the self() method.


// From within an Actor
greeter.tell(new Greet(), self());
        

If you choose not to pass in a sender reference into the tell method, or forget it, then a reference to the 'dead-letter' Actor will be used. The 'dead-letter' Actor is where all unhandled messages end up, and you can use Akka's Event Bus to subscribe on them.

The 'sender' reference

This sender reference will then be available in the receiver Actor when it's processing the message. Since each message is paired with its unique sender reference, the "current" sender reference will change with each new message you process. So if you for some reason need to use a specific sender reference later then you have to hold on to it, storing it away in a member field or similar. In Java you can access it using the sender() method.


// From within the Greeter Actor
sender().tell(new Greeting(greeting), self());
        

Using Inbox

Most real-world Actor applications make use of more than one Actor. The inventor of the Actor Model, Carl Hewitt, recently said in an interview that; "One Actor is no Actor. Actors come in systems." This is important wisdom. To truly leverage the Actor Model you should use lots of Actors. Every hard problem in Actor programming can be solved by adding more Actors; by breaking down the problem into subtasks and delegate by handing them to new Actors.

However, for simplicity we are just using a single Actor in this sample. This means that if we communicate with this single actor from a main program then we have no sender, since we are not communicating with the Actor from within another Actor. Luckily Akka has a nice solution to this problem; Inbox.

Inbox allows you to create an "actor-in-a-box", i.e. it contains an Actor which can be used as a puppet for sending messages to other Actors and receiving their replies. You can create an Inbox using Inbox.create and send messages from it using inbox.send. The internal Actor will just put any message it receives into a queue from which it can be retrieved by calling inbox.receive; if the queue is empty then that call will block until a message becomes available. Pretty simple.

As you probably know, blocking is something that can really inhibit performance and scalability, and that you should use very sparingly and with care. That said, we are making use of it in this sample since it simplifies the sample and makes it very easy to follow the message flow.

Now let's complete this tutorial by writing the driver code that will exercise our Greeter Actor.


// Create an "actor-in-a-box"
final Inbox inbox = Inbox.create(system);

// Tell the 'greeter' to change its 'greeting' message
greeter.tell(new WhoToGreet("akka"), ActorRef.noSender());

// Ask the 'greeter for the latest 'greeting'
// Reply should go to the mailbox
inbox.send(greeter, new Greet());

// Wait 5 seconds for the reply with the 'greeting' message
Greeting greeting = (Greeting) inbox.receive(Duration.create(5, "seconds"));
System.out.println("Greeting: " + greeting.message);
        

Run the App

Congratulations!!!

Now you have almost completed the tutorial and written a simple Akka application. If you have not looked at the full sample then now is a good time to do so: HelloAkka.java

Let's have some fun and run it.

In Run select Start (if the app is not already running). Feel free to modify, compile and re-run the sample.

Next Steps

The Akka Documentation explains each one of the topics covered in this tutorial in great depth, and much much more. Check out the Java Manual for more information using Akka with Java and Lambdas.

The Akka Team blog; Let It Crash has a lot of articles and can be a good additional source of information.

If you have questions don't hesitate to post them to the akka-user Google Group.

comments powered by Disqus