Channels ▼
RSS

Tools

JVM Concurrency and Actors with GPars


Continuations

A stateful actor's code is processed in chunks, separated by quiet periods of waiting for new events (messages). This can be naturally modeled through continuations. However, since JVM doesn't support continuations directly, they have to be simulated in the actor frameworks, which has a slight impact on organization of the actors' code.

Calling the react() method from within the actor's code has slightly different semantics than just reading the next message from the actor's inbox. Under the covers, the closure supplied as a parameter to the react method is scheduled for processing once a message becomes available. The scheduling is the last work the current thread does on the actor's behalf. Once scheduled, the thread is detached from the actor and returned to the pool to serve other actors.

To allow detaching actors from the threads, the react() method requires that the code to be written in a special "Continuation-style."

 
def myActor = Actors.actor {
    loop {
        react {msg1 ->
            ...
            react {msg2 ->
                ...
            }
            // Never reached
        }
        // Never reached
    }
    // Never reached
}

Essentially, react() schedules the supplied code (closure) to be executed upon next message arrival and quits the actor body. The closure supplied to the react() methods is the code where the computation should continue. Thus, we have continuation style.

The loop() method allows iteration within the actor body. Unlike typical looping constructs, loop() cooperates with nested react() blocks and ensures looping across subsequent message retrievals.

Stateful Actors Used from Java

You may see that stateful actors use nested closures heavilly to organize their bodies. Although it is possible to encode a nested actor's body in Java using anonymous inner classes for react's parameters, sticking to Groovy can save you a lot of typing and considerably reduce verbosity of the code.

Active Objects

Active objects give actors an OO facade, allowing you to program in a more traditional OO style. You avoid dealing directly with the actor machinery, sending messages, defining message handlers and sending or waiting for replies.

import groovyx.gpars.activeobject.ActiveObject
import groovyx.gpars.activeobject.ActiveMethod

@ActiveObject
class Decryptor {
    @ActiveMethod
    def decrypt(String encryptedText) {
        return encryptedText.reverse()
    }
    @ActiveMethod
    def decrypt(Integer encryptedNumber) {
        return -1*encryptedNumber + 142
    }
}

final Decryptor decryptor = new Decryptor()

def part1 = decryptor.decrypt(' noitcA ni yvoorG')
def part2 = decryptor.decrypt(140)
def part3 = decryptor.decrypt('noittide dn')

print part1.get()
print part2.get()
println part3.get()

As you can see in the code example above, active objects are plain POGOs (Plain Old Groovy Objects) annotated with the @ActiveObject annotation. Where they differ from ordinary objects is their behavior upon method invocation. Leveraging Groovy compile-time code transformations, whenever any of the active methods (marked as @ActiveMethod) are called, GPars translates the method calls to messages being sent to the object's internal actor. The internal (hidden) actor then handles these messages asynchronously by invoking the desired functionality in its own context.

Because the code now runs asynchronously and doesn't block the caller, we need a new way to propagate the return values up to the caller. The mechanism is commonly referred to as "Future" or "Promise." Active methods return such Promises instead of real results, which by themselves are only handles allowing the caller to obtain the result once it is calculated. The part1, part2 and part3 variables in the preceding code example above are these "Promises." The script calls their get() method to retrieve the return value.

Because this mechanism relies on compile-time meta-programming, active objects must be implemented in Groovy. However, once created they can be invoked from Java just like from Groovy.

Summary

GPars brings together several handy concurrency abstractions. This article was dedicated to the actors concept, which is (along with Communicating Sequential Processes (CSP) and dataflow) one of the popular message-passing paradigms. We have seen how actors are created and invoked both in Groovy and in Java and how active objects can be used to give actors a familiar OO face.

GPars toolset

Because there is no single answer to all the concurrency challenges, GPars provides more than just actors, It includes:

  • Agents
  • Dataflow concurrency
  • Communicating Sequential Processes
  • Parallel collections
  • Fork/Join capabilities
  • Composable asynchronous functions

This wide range of operations enables developers to pick the best tool for their job. Going into details of each of these abstractions is, however, beyond the scope of this article. The best way to see GPars in its entirety is to check out the GPars User Guide.


Václav is a programming enthusiast who's constantly seeking ways to make development more effective and enjoyable. He's particularly interested in server-side Java technologies, distributed systems and concurrency. You can check out his blog or follow him on twitter.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video