You are on page 1of 6

(/)

Asynchronous Programming in Java


Last updated: May 11, 2023

Written by: Anshul Bansal (https://www.baeldung.com/author/anshulbansal)

Java Concurrency (https://www.baeldung.com/category/java/java-concurrency)

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:
>> CHECK OUT THE COURSE (/ls-course-start)

1. Overview
With the growing demand for writing non-blocking code, we need ways to execute the code asynchronously.
In this tutorial, we'll look at a few ways to achieve asynchronous programming (/cs/async-vs-multi-threading) in Java. We'll also explore a few Java libraries that
provide out-of-the-box solutions.

Further reading:
Guide To CompletableFuture (/java-completablefuture)
Quick and practical guide to Java 8's CompletableFuture.
Read more (/java-completablefuture) →

Design Principles and Patterns for Highly Concurrent Applications (/concurrency-principles-patterns)


A quick and practical overview of design principles for highly concurrent applications!
Read more (/concurrency-principles-patterns) →

How To Do @Async in Spring (/spring-async)


How to enable and use @Async in Spring - from the very simple config and basic usage to the more complex executors and exception handling strategies.
Read more (/spring-async) →

2. Asynchronous Programming in Java

2.1. Thread
We can create a new thread to perform any operation asynchronously. With the release of lambda expressions (/java-8-lambda-expressions-tips) in Java 8, it's cleaner
and more readable.
Let's create a new thread that computes and prints the factorial of a number:

int number = 20;


Thread newThread = new Thread(() -> {
System.out.println("Factorial of " + number + " is: " + factorial(number));
});
newThread.start();

2.2. FutureTask
Since Java 5, the Future interface provides a way to perform asynchronous operations using the FutureTask (/java-future#1-implementing-futures-with-futuretask).
We can use the submit method of the ExecutorService (https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ExecutorService.html)
to perform the task asynchronously and return the instance of the FutureTask.
So let's find the factorial of a number:
ExecutorService threadpool = Executors.newCachedThreadPool();
Future<Long> futureTask = threadpool.submit(() -> factorial(number));

while (!futureTask.isDone()) {
System.out.println("FutureTask is not finished yet...");
}
long result = futureTask.get();

threadpool.shutdown();

Here we've used the isDone method provided by the Future interface to check if the task is completed. Once finished, we can retrieve the result using the get method.

2.3. CompletableFuture
Java 8 introduced CompletableFuture (/java-completablefuture) with a combination of a Future and CompletionStage
(https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/CompletionStage.html). It provides various methods like supplyAsync,
runAsync, and thenApplyAsync for asynchronous programming.
Now let's use the CompletableFuture in place of the FutureTask to find the factorial of a number:
AD

(https://ads.freestar.com/?
CompletableFuture<Long> completableFuture = CompletableFuture.supplyAsync(() -> utm_campaign=branding&utm_medium=banner&utm_source=baeldung.com&utm_conten
factorial(number));
while (!completableFuture.isDone()) { mid_2)
System.out.println("CompletableFuture is not finished yet...");
}
long result = completableFuture.get();

We don't need to use the ExecutorService explicitly. The CompletableFuture internally uses ForkJoinPool (/java-fork-join) to handle the task asynchronously.
Thus, it makes our code a lot cleaner.

3. Guava
Guava (/guava-21-new) provides the ListenableFuture (https://guava.dev/releases/28.2-jre/api/docs/index.html?
com/google/common/util/concurrent/ListenableFuture.html) class to perform asynchronous operations.
First, we'll add the latest guava (https://mvnrepository.com/artifact/com.google.guava/guava) Maven dependency:

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>

Then let's find the factorial of a number using the ListenableFuture:

ExecutorService threadpool = Executors.newCachedThreadPool();


ListeningExecutorService service = MoreExecutors.listeningDecorator(threadpool);
ListenableFuture<Long> guavaFuture = (ListenableFuture<Long>) service.submit(()-> factorial(number));
long result = guavaFuture.get();

Here the MoreExecutors (https://guava.dev/releases/28.2-jre/api/docs/index.html?com/google/common/util/concurrent/MoreExecutors.html) class provides the


instance of the ListeningExecutorService (https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ExecutorService.html) class. Then
the ListeningExecutorService.submit method performs the task asynchronously and returns the instance of the ListenableFuture.
Guava also has a Futures (https://guava.dev/releases/28.2-jre/api/docs/com/google/common/util/concurrent/Futures.html) class that provides methods
like submitAsync, scheduleAsync, and transformAsync to chain the ListenableFutures, similar to the CompletableFuture.
For instance, let's see how to use Futures.submitAsync in place of the ListeningExecutorService.submit method:

ListeningExecutorService service = MoreExecutors.listeningDecorator(threadpool);


AsyncCallable<Long> asyncCallable = Callables.asAsyncCallable(new Callable<Long>() {
public Long call() {
return factorial(number);
}
}, service);
ListenableFuture<Long> guavaFuture = Futures.submitAsync(asyncCallable, service);

Here the submitAsync method requires an argument of AsyncCallable (https://guava.dev/releases/28.2-


jre/api/docs/com/google/common/util/concurrent/AsyncCallable.html), which is created using the Callables (https://guava.dev/releases/28.2-
jre/api/docs/com/google/common/util/concurrent/Callables.html) class.
Additionally, the Futures class provides the addCallback method to register the success and failure callbacks:

Futures.addCallback(
factorialFuture,
new FutureCallback<Long>() {
public void onSuccess(Long factorial) {
System.out.println(factorial);
}
public void onFailure(Throwable thrown) {
thrown.getCause();
}
},
service);

4. EA Async
Electronic Arts brought the async-await feature from .NET to the Java ecosystem through the ea-async library (https://github.com/electronicarts/ea-async).
This library allows writing asynchronous (non-blocking) code sequentially. Therefore, it makes asynchronous programming easier and scales naturally.
First, we'll add the latest ea-async (https://mvnrepository.com/artifact/com.ea.async/ea-async) Maven dependency to the pom.xml:

<dependency>
<groupId>com.ea.async</groupId>
<artifactId>ea-async</artifactId>
<version>1.2.3</version>
</dependency>

Then we'll transform the previously discussed CompletableFuture code by using the await method provided by EA's Async (https://javadoc.io/doc/com.ea.async/ea-
async/latest/com/ea/async/Async.html) class:

static {
Async.init();
}

public long factorialUsingEAAsync(int number) {


CompletableFuture<Long> completableFuture = CompletableFuture.supplyAsync(() -> factorial(number));
long result = Async.await(completableFuture);
}

Here we make a call to the Async.init method in the static block to initialize the Async runtime instrumentation.
Async instrumentation transforms the code at runtime, and rewrites the call to the await method to behave similarly to using the chain of CompletableFuture.
Therefore, the call to the await method is similar to calling Future.join.
We can use the – javaagent JVM parameter for compile-time instrumentation. This is an alternative to the Async.init method:

java -javaagent:ea-async-1.2.3.jar -cp <claspath> <MainClass>

Now let's look at another example of writing asynchronous code sequentially.


First, we'll perform a few chain operations asynchronously using the composition methods like thenComposeAsync and thenAcceptAsync of the CompletableFuture
class:

CompletableFuture<Void> completableFuture = hello()


.thenComposeAsync(hello -> mergeWorld(hello))
.thenAcceptAsync(helloWorld -> print(helloWorld))
.exceptionally(throwable -> {
System.out.println(throwable.getCause());
return null;
});
completableFuture.get();

Then we can transform the code using EA's Async.await():

try {
String hello = await(hello());
String helloWorld = await(mergeWorld(hello));
await(CompletableFuture.runAsync(() -> print(helloWorld)));
} catch (Exception e) {
e.printStackTrace();
}

The implementation resembles the sequential blocking code; however, the await method doesn't block the code.
As discussed, all calls to the await method will be rewritten by the Async instrumentation to work similarly to the Future.join method.
So once the asynchronous execution of the hello method is finished, the Future result is passed to the mergeWorld method. Then the result is passed to the last
execution using the CompletableFuture.runAsync method.

5. Cactoos
Cactoos is a Java library based on object-oriented principles.
It's an alternative to Google Guava and Apache Commons that provides common objects for performing various operations.
First, let's add the latest cactoos (https://mvnrepository.com/artifact/org.cactoos/cactoos) Maven dependency:

<dependency>
<groupId>org.cactoos</groupId>
<artifactId>cactoos</artifactId>
<version>0.43</version>
</dependency>

This library provides an Async (https://javadoc.io/doc/org.cactoos/cactoos/latest/org/cactoos/func/Async.html) class for asynchronous operations.


So we can find the factorial of a number using the instance of Cactoos's Async class:

Async<Integer, Long> asyncFunction = new Async<Integer, Long>(input -> factorial(input));


Future<Long> asyncFuture = asyncFunction.apply(number);
long result = asyncFuture.get();

Here the apply method executes the operation using the ExecutorService.submit method, and returns an instance of the Future interface.
AD

Similarly, the Async class has the exec method that provides the same feature without a return value. (https://ads.freestar.com/?
utm_campaign=branding&utm_medium=banner&utm_source=baeldung.com&utm_content
Note: the Cactoos library is in the initial stages of development and may not be appropriate for production use yet.
6. Jcabi-Aspects
Jcabi-Aspects provides the @Async (https://aspects.jcabi.com/apidocs-0.22.6/com/jcabi/aspects/Async.html) annotation for asynchronous programming through
AspectJ (/aspectj) AOP aspects.
First, let's add the latest jcabi-aspects (https://mvnrepository.com/artifact/com.jcabi/jcabi-aspects) Maven dependency:

<dependency>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-aspects</artifactId>
<version>0.22.6</version>
</dependency>

The jcabi-aspects library requires AspectJ runtime support, so we'll add the aspectjrt (https://mvnrepository.com/artifact/org.aspectj/aspectjrt) Maven dependency:

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>

Next, we'll add the jcabi-maven-plugin (https://mvnrepository.com/artifact/com.jcabi/jcabi-maven-plugin) plugin that weaves the binaries with AspectJ aspects. The
plugin provides the ajc goal that does all the work for us:

<plugin>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-maven-plugin</artifactId>
<version>0.14.1</version>
<executions>
<execution>
<goals>
<goal>ajc</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
</dependencies>
</plugin>

Now we're all set to use the AOP aspects for asynchronous programming:

@Async
@Loggable
public Future<Long> factorialUsingJcabiAspect(int number) {
Future<Long> factorialFuture = CompletableFuture.supplyAsync(() -> factorial(number));
return factorialFuture;
}

When we compile the code, the library will inject AOP advice in place of the @Async annotation through AspectJ weaving, for the asynchronous execution of the
factorialUsingJcabiAspect method.
Let's compile the class using the Maven command:

mvn install

The output from the jcabi-maven-plugin may look like:

--- jcabi-maven-plugin:0.14.1:ajc (default) @ java-async ---


[INFO] jcabi-aspects 0.18/55a5c13 started new daemon thread jcabi-loggable for watching of @Loggable annotated methods
[INFO] Unwoven classes will be copied to /tutorials/java-async/target/unwoven
[INFO] jcabi-aspects 0.18/55a5c13 started new daemon thread jcabi-cacheable for automated cleaning of expired @Cacheable values
[INFO] ajc result: 10 file(s) processed, 0 pointcut(s) woven, 0 error(s), 0 warning(s)

We can verify if our class is woven correctly by checking the logs in the jcabi-ajc.log file generated by the Maven plugin:

Join point 'method-execution(java.util.concurrent.Future


com.baeldung.async.JavaAsync.factorialUsingJcabiAspect(int))'
in Type 'com.baeldung.async.JavaAsync' (JavaAsync.java:158)
advised by around advice from 'com.jcabi.aspects.aj.MethodAsyncRunner'
(jcabi-aspects-0.22.6.jar!MethodAsyncRunner.class(from MethodAsyncRunner.java))

Then we'll run the class as a simple Java application, and the output will look like:

17:46:58.245 [main] INFO com.jcabi.aspects.aj.NamedThreads -


jcabi-aspects 0.22.6/3f0a1f7 started new daemon thread jcabi-loggable for watching of @Loggable annotated methods
17:46:58.355 [main] INFO com.jcabi.aspects.aj.NamedThreads -
jcabi-aspects 0.22.6/3f0a1f7 started new daemon thread jcabi-async for Asynchronous method execution
17:46:58.358 [jcabi-async] INFO com.baeldung.async.JavaAsync -
#factorialUsingJcabiAspect(20): 'java.util.concurrent.CompletableFuture@14e2d7c1[Completed normally]' in 44.64µs

As we can see, a new daemon thread, jcabi-async, is created by the library that performed the task asynchronously.
Similarly, the logging is enabled by the @Loggable (https://aspects.jcabi.com/apidocs-0.22.6/com/jcabi/aspects/Loggable.html) annotation provided by the library.
7. Conclusion
In this article, we learned a few ways of asynchronous programming in Java.
To begin with, we explored Java's in-built features like FutureTask and CompletableFuture for asynchronous programming. Then we examined a few libraries, like EA
Async and Cactoos, with out-of-the-box solutions.
AD

We also discussed the support of performing tasks asynchronously using Guava's ListenableFuture and Futures classes. Finally, (https://ads.freestar.com/?
we touched on the jcabi-AspectJ
utm_campaign=branding&utm_medium=banner&utm_source=baeldung.com&utm_content
library that provides AOP features through its @Async annotation for asynchronous method calls.
As usual, all the code implementations are available over on GitHub (https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-concurrency-
advanced-3).

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:
>> CHECK OUT THE COURSE (/ls-course-end)

Learning to build your API


with Spring?
Download the E-book (/rest-api-spring-

guide)

2 COMMENTS   Oldest 

View Comments

Comments are closed on this article!

COURSES
ALL COURSES (/ALL-COURSES)
ALL BULK COURSES (/ALL-BULK-COURSES)
ALL BULK TEAM COURSES (/ALL-BULK-TEAM-COURSES)
THE COURSES PLATFORM (HTTPS://COURSES.BAELDUNG.COM)

SERIES
JAVA “BACK TO BASICS” TUTORIAL (/JAVA-TUTORIAL)
JACKSON JSON TUTORIAL (/JACKSON)
APACHE HTTPCLIENT TUTORIAL (/HTTPCLIENT-GUIDE)
REST WITH SPRING TUTORIAL (/REST-WITH-SPRING-SERIES)
SPRING PERSISTENCE TUTORIAL (/PERSISTENCE-WITH-SPRING-SERIES)
SECURITY WITH SPRING (/SECURITY-SPRING)
SPRING REACTIVE TUTORIALS (/SPRING-REACTIVE-GUIDE)

ABOUT
ABOUT BAELDUNG (/ABOUT)
THE FULL ARCHIVE (/FULL_ARCHIVE)
EDITORS (/EDITORS)
JOBS (/TAG/ACTIVE-JOB/)
OUR PARTNERS (/PARTNERS)
PARTNER WITH BAELDUNG (/ADVERTISE)

TERMS OF SERVICE (/TERMS-OF-SERVICE)


PRIVACY POLICY (/PRIVACY-POLICY)
COMPANY INFO (/BAELDUNG-COMPANY-INFO)
CONTACT (/CONTACT)

You might also like