Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Akka: Deep Dive

DZone's Guide to

Akka: Deep Dive

This look into Akka revolves around dispatchers and how they help actors get to their final destination while also allowing concurrent behavior.

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

Akka is very easy to use and has successfully abstracted the complexity of concurrency. That's all the more reason we should try to understand how it achieves this abstraction. I wanted to go deep inside Akka and understand the relationship between an Actor and a Thread, where we can spawn 2,000 threads and, on same machine, how we can spawn 500,000 Actors.

Diving In

At first, I thought that there are probably several actors for each thread that work in a cooperative multitasking mode. But this assumption complicates things a lot. So, is there a simpler explanation? Have we solved the same kind of problem before? Didn’t we do that in a multi-processing environment, where a process waiting for I/O makes way for the next process? Yes, task schedulers like in OSes can be a good approach as well. It makes much more sense than the scheme I assumed earlier.

What task schedulers do in OSes, dispatchers do in Akka. It holds all actors, threads, and messages. And when resources become available and there are messages available for processing, the dispatcher activates. It takes the appropriate Actor object, wraps its receive method in a runnable and passes it to a spare thread.  

Before understanding the dispatcher in Akka, let us understand the dispatcher pattern.

Dispatcher Pattern

Dispatchers are used to control the flow of execution. Based on the dispatching policy, dispatchers will route incoming messages to their respective destinations. Just like in a post office, where all the letters are collected in a single office and then, according to the addresses, they are dispatched further to their destination.

As we already discussed, the dispatcher is the heart of AKKA. It holds all the Actors and schedules the executions based on the availability of resources. We have already used a similar thing in the form of Executors in Java.

The Concurrency API introduces the concept of an ExecutorService as a higher level replacement for working with threads directly. Executors are capable of running asynchronous tasks and typically manage a pool of threads, so we don't have to create new threads manually. All threads of the internal pool will be reused under the hood for revenant tasks, so we can run as many concurrent tasks as we want throughout the life-cycle of our application with a single executor service.

The dispatcher in Akka is modeled along similar lines. It also provides the use of different types of dispatchers. Let us understand dispatcher in more detail.

Types of Dispatchers

Following are lines taken from the Akka documentation:

1. Dispatcher

  • This is an event-based dispatcher that binds a set of Actors to a thread pool. It is the default dispatcher used if one is not specified.
  • Sharability: Unlimited.
  • Mailboxes: Any, creates one per Actor.
  • Use cases: Default dispatcher, Bulkheading.
  • Driven by: java.util.concurrent.ExecutorService.

2. PinnedDispatcher

  • This dispatcher dedicates a unique thread for each actor using it; i.e. each actor will have its own thread pool with only one thread in the pool.
  • Sharability: None
  • Mailboxes: Any, creates one per Actor
  • Use cases: Bulkheading

Driven by: Any akka.dispatch.ThreadPoolExecutorConfigurator by default a "thread-pool-executor"

3. BalancingDispatcher

  • This is an executor based event driven dispatcher that will try to redistribute work from busy actors to idle actors.
  • All the actors share a single Mailbox that they get their messages from.
  •  It is assumed that all actors using the same instance of this dispatcher can process all messages that have been sent to one of the actors; i.e. the actors belong to a pool of actors, and to the client, there is no guarantee about which actor instance actually processes a given message.
  • Sharability: Actors of the same type only.
  • Mailboxes: Any, creates one for all Actors.
  • Use cases: Work-sharing.

Driven by: java.util.concurrent.ExecutorService

4. CallingThreadDispatcher

  • This dispatcher runs invocations on the current thread only. This dispatcher does not create any new threads, but it can be used from different threads concurrently for the same actor.
  • Sharability: Unlimited.
  • Mailboxes: Any, creates one per Actor per Thread (on demand).
  • Use cases: Testing.
  • Driven by: The calling thread (duh).

More Dispatcher Configuration Examples

Configuring a dispatcher with a fixed thread pool size, e.g. for Actors that perform blocking IO:

blocking-io-dispatcher {
    type = Dispatcher
    executor = "thread-pool-executor"
    thread-pool-executor {
        fixed-pool-size = 32
    }
    throughput = 1
}


And then using it:

val myActor =
              context.actorOf(Props[MyActor].withDispatcher("blocking-io-dispatcher"), "myactor2")


Configuring a PinnedDispatcher:

my-pinned-dispatcher {
    executor = "thread-pool-executor"
    type = PinnedDispatcher
}


And then using it:

val myActor =
          context.actorOf(Props[MyActor].withDispatcher("my-pinned-dispatcher"), "myactor3")

 

To properly utilize the power of Akka, we must understand the types of dispatchers and correctly use the right one.

Similarly to the dispatcher, there are four default mailbox implementations, provided as follows:

  • Unbounded mailbox.
  • Bounded mailbox.
  • Unbounded priority mailbox.
  • Bounded priority mailbox.

There are many more types of mailboxes in Akka, and it also lets you define your own mailbox.

So to summarize, threads are the underlying resources and are optimized based on the available CPU cores and the type of application workload. The number of threads is configured in conjunction with the dispatcher policy employed for the application.

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:
akka ,java ,dispatcher ,tutorial ,concurrency

Published at DZone with permission of Prateek Kulkarni. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}