Callable Future Example

Learn to execute callable tasks (which return a result of type Future after execution) using ExecutorService implementations in this simple Callable Future example.

1. Important interfaces

1.1. Callable

In Java concurrency, Callable represents a task that returns a result. Executor can run callable tasks – concurrently.

Since Java 8, it is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

@FunctionalInterface
public interface Callable<V> {
/**
 * Computes a result, or throws an exception if unable to do so.
 *
 * @return computed result
 * @throws Exception if unable to compute a result
 */

V call() throws Exception;
}

1.2. Future

Future interface has methods to obtain the result generated by a Callable object and manage its state. It represents the result of an asynchronous computation.

The result can only be retrieved using method get() when the computation has completed, blocking if necessary until it is ready.

Cancellation of a task is performed by the cancel() method. Once a computation has completed, the computation cannot be cancelled.

public interface Future<V> 
{
	boolean cancel(boolean mayInterruptIfRunning);

	boolean isCancelled();

	boolean isDone();

	V get() throws InterruptedException, ExecutionException;

	V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

2. Callable Future Example

In this example, we are creating a task which will return the factorial of a given number. The return value of the task after it’s completion is the factorial of argument number.

class FactorialCalculator implements Callable<Integer> 
{
	private final Integer number;

	public FactorialCalculator(Integer number) {
		this.number = number;
	}

	@Override
	public Integer call() throws Exception {

		int result = 1;

		if ((number == 0) || (number == 1)) {
			result = 1;
		} else {
			for (int i = 2; i <= number; i++) {
				result *= i;
				TimeUnit.MILLISECONDS.sleep(20);
			}
		}

		System.out.printf("Factorial of %d is :: %d\n", number, result);
		return result;
	}
}

Now when the calculator is ready, we will use ExecutorService to execute the tasks. Here we will create 10 tasks which will compute factorial of numbers 1 to 10.

Each task will be submitted to ExecutorService internally managing thread pool of 2 threads.

We will use method awaitTermination() to wait for all tasks to complete before checking the output of all tasks.It is optional step, and we are allowed not to wait and start checking the outputs as an when a task is complete.

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Main 
{
	public static void main(String[] args) throws InterruptedException 
	{
		ExecutorService executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);

		List<Future<Integer>> resultList = new ArrayList<>();

		for (int i = 1; i <= 10; i++) {
			FactorialCalculator calculator = new FactorialCalculator(i);
			Future<Integer> result = executor.submit(calculator);
			resultList.add(result);
		}
		
		executor.awaitTermination(5, TimeUnit.SECONDS);

		for (int i = 0; i < resultList.size(); i++) 
		{
			Future<Integer> result = resultList.get(i);
			Integer number = null;
			try {
				number = result.get();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
			System.out.printf("Main: Task %d: %d\n", i, number);
		}

		executor.shutdown();
	}
}

Program output.

Factorial of 1 is :: 1
Factorial of 2 is :: 2
Factorial of 3 is :: 6
Factorial of 4 is :: 24
Factorial of 5 is :: 120
Factorial of 6 is :: 720
Factorial of 7 is :: 5040
Factorial of 8 is :: 40320
Factorial of 9 is :: 362880
Factorial of 10 is :: 3628800

Main: Task 0: 1
Main: Task 1: 2
Main: Task 2: 6
Main: Task 3: 24
Main: Task 4: 120
Main: Task 5: 720
Main: Task 6: 5040
Main: Task 7: 40320
Main: Task 8: 362880
Main: Task 9: 3628800

In above example, when we send callable object to be executed in an executor using the submit() method, it returns a Future object that you can use with two main objectives:

3. Conclusion

Above example demonstrate that –

  • We can control the status of the task i.e. we can cancel the task after checking whether it has finished or not. For this purpose, we can use the isDone() method.
  • We can get the result returned using get() method. This method waits until the Callable object has finished the execution of the call() method and has returned its result.
  • If the thread is interrupted while the get() method is waiting for the result, it throws an InterruptedException exception.
  • If the call() method throws an exception, then the get() method throws an ExecutionException exception as well.

Drop me your questions related to Java ExecutorService Callable Example in comments.

Happy Learning !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.