Java Multithreading Tutorial With Example

CompletableFuture in Java with Example

Java 8 introduced many important features including lambdas, stream, etc.

CompletableFuture is also one of the most important features added in Java 8 which is useful in asynchronous programming.

If you are not aware of asynchronous programming, it is a form of parallel programming that allows a particular code block to run separately from the main thread and notifies the caller thread of its statuses like completion, failure or progress.

The main advantage of asynchronous programming is you can write non-blocking code that doesn’t block the main thread at all.

Therefore, your application will become more responsive and performance will increase.

Before we go further to create a few examples, let see what is the difference between Future and CompletableFuture?

Using CompletableFuture like a simple Future

public class CompletableFuture<T> implements Future<T>, CompletionStage<T>

CompletableFuture implements the Future , which means that it can be used to launch a task and retrieve a result later with the get () method.

However, it brings a lot more functionality. It also implements the new CompletionStage interface, which is also introduced in 1.8.

Let’s create a simple example.

package com.codedelay.concurrency;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class CompletableFutureDemo {
	private static final CompletableFuture<String> COMPLETABLE_FUTURE = new CompletableFuture<>();;
	public void performAsync() throws InterruptedException {
		Thread t1 = new Thread(() -> {
			try {
			} catch (InterruptedException e) {
	public static void main(String[] args) {
		CompletableFutureDemo cfd = new CompletableFutureDemo();
		try {
			System.out.println("get()->   " + COMPLETABLE_FUTURE.get());
			System.out.println("isDone  " + COMPLETABLE_FUTURE.isDone());
		} catch (InterruptedException e) {
		}  catch (ExecutionException e) {

In the above example, we have created an instance of CompletableFuture using no-arg constructor.

Hence, any client API who want to get the result from performAsync can call get() to get the result from the CompletableFuture.

System.out.println("returnStr " + returnStr.get());

In the above example get() method blocks until and unless the Future completes its task.

To avoid blocking the get() call forever, Let’s use completableFuture.complete();

COMPLETABLE_FUTURE.complete("Hello World!!");

completableFuture.complete () manually complete the Future.

To put it differently, all the client APIs who are waiting for the Future will get the result “Hello World”.

Multiple complete() call will be ignored.

COMPLETABLE_FUTURE.complete("Hello World!!");

The output of the above program would be:

Hello World!!

CompletableFuture can throw Exceptions

CompletableFuture can also return/throw an exception using completeExceptionally method.

COMPLETABLE_FUTURE.completeExceptionally(new RuntimeException());
java.util.concurrent.ExecutionException: java.lang.RuntimeException
	at java.base/java.util.concurrent.CompletableFuture.reportGet(
	at java.base/java.util.concurrent.CompletableFuture.get(
	at com.codedelay.concurrency.CompletableFutureDemo.main(
Caused by: java.lang.RuntimeException
	at com.codedelay.concurrency.CompletableFutureDemo.lambda$0(
	at java.base/

CompletableFuture can cancel() the execution

Suppose if you are not able to continue running performAsync and you want to cancel the asynchronous execution, then you can also cancel the execution using the cancel() method.


If we are blocked for result by calling get() method, then it will throw CancellationException.

Exception in thread "main" true
	at java.base/java.util.concurrent.CompletableFuture.cancel(
	at com.codedelay.concurrency.CompletableFutureDemo.lambda$0(
	at java.base/

Encapsulate a task using runAsync and supplyAsync

If you want to ignore the return value and simply want to execute code asynchronously then we can use runAsync orsupplyAsync.

runAsync or supplyAsync are static methods that allow us to create a CompletableFuture instance from the Runnable and Supplier functional types accordingly.

static CompletableFuture<Void> runAsync(Runnable runnable)

runAsync takes Runnable and returns CompletableFuture.

static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)

supplyAsync takes Supplier and returns CompletableFuture.

Click to rate this post!
[Total: 0 Average: 0]

Leave a Reply

Your email address will not be published. Required fields are marked *

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