Async await in Java

Writing asynchronous code is hard. Trying to understand what asynchronous code is supposed to be doing is even harder. Promises are a common way to attempt to describe the flow of delayed-execution: first do a thing, then do another thing, in case of error do something else.

In many languages promises have become the de facto way to orchestrate asynchronous behaviour. Java 8 finally got with the program and introduced CompletableFuture; although seriously, who designed the API? It’s a mess!

The trouble with promises is  that the control flow can become anything but simple. As the control flow becomes more complex it becomes virtually impossible to understand (do this, then that, unless it’s Wednesday, in which case do this other thing, if there’s an error go back three spaces, yada yada yada).

The cool kids have moved on to using async…await. C# has it. JavaScript has it. And now… and now, via some of the big brains at EA, Java has it! Yes, Java has a usable async…await construct, without changing the language!

A simple example: we could compose a couple of asynchronous operations using CompletableFuture as follows:

private static void theOldWay() {
    doAThing()
            .thenCompose(Main::doAnotherThing)
            .thenAccept(Main::reportSuccess)
            .exceptionally(Main::reportFailure);
}

This should be pretty simple to follow, often code using futures is very far from this simple. But with the magic of EA’s async await we can re-write it like this:

private static CompletableFuture<Void> theNewWay() {
    try {
        String intermediate = await(doAThing());
        String result = await(doAnotherThing(intermediate));
        reportSuccess(result);
    } catch (Throwable t) {
        reportFailure(t);
    }
    return completedFuture(null);
}

It looks like synchronous code. But the calls to Async.await are magic. These calls are re-written (at runtime or build time, as you prefer) to make the calls non-blocking!

The code is much easier to write, much easier to read, a million times easier to debug and most importantly it scales naturally. As code becomes more complex you can use normal refactoring tools to keep it under control. With CompletableFutures you end up passing around all these future objects and, somewhere along the line, one day you’re going to miss a code path and boom! One free bug in production.

So even if you’re stuck using Java, you can still be like the cool kids and use async…await!

7 thoughts on “Async await in Java

  1. Let me plug a link to my own library for Async/Await in Java: https://github.com/vsilaev/tascalate-async-await

    It’s about to be released shortly (need to add some documentation, the code itself is complete). Comparing to the EA implementation it has several benefits:

    1. EA implementation neither let you specify where your code will be resumed once await-ed nor it provides a way to capture execution context before suspend and restore it after resume. Trust me, it’s an ultimate requirement in managed environment like JEE or JavaFX. My library has the Scheduler (direct analogy is SynchronizationContext in .NET) and SchedulerResolver – that lets you get an effective Scheduler implicitly or explicitly.

    2. In EA implementation there is no way to cancel async method from the outside. In .NET there is the CancellationToken that provides necessary functionality, though, a bit inconvenient to use. In my Tascalate Async/Await it’s possible to use Future.cancel() to truly interrupt execution of async method (typically, blocking and/or IO-Bound). At least, it’s guaranteed to interrupt async method once it’s entered “awaiting” state. For CPU-bound computational async methods there is an option to check for interruption flag and exit early cooperatively.

    4. Asynchronous (lazy) generators — this feature is not available neither in .NET nor in EA Java implementation, but exists in upcoming ECMAScipt 2018. Very powerful concept — it let you write efficient “single consumer + lazy pull producer” – pretty common pattern, that frequently is more appropriate than Rx “multiple consumers + active push producer (events emitter, observable, etc..)”

    Your feedback is welcome!

    1. Is there a way to run unit tests inside an ide, without the maven build? With the ea library I could use Async.init() in the test and it would do the byte code rewriting at runtime

      1. Yes!!! And it’s a huge topic to discuss! Shortly, you must specify Scheduler to define where to resume code. Typically Scheduler wraps Executor/ExecutorService.

        The simplest option is to explicitly add annotated “@SchedulerProvider Scheduler myScheduler” parameter to the async method.

        But there are several options to specify implicit Scheduler via SchedulerResolver. Concrete resolvers are located in net.tascalate.async.resolver.* subprojects – it’s possible to inherit Scheduler of the active async call (if any), specify scoped thread-local Scheduler or use static/instance field/getter of the class containing async method. You can even combine several approaches! Need to add a documentation about this feature – it’s both powerful and complex!

        P.S. sorry about late reply – I get no notifications about your comments. Now I’ve subscribed! ))

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.