Java Callable Future Example

One of the benefits of the Java executor framework is that we can run concurrent tasks that may return a single result after processing the tasks. The Java Concurrency API achieves this with the following two interfaces Callable and Future.

In this tutorial, we will learn to execute Callable tasks (which return a result of type Future after execution) using ExecutorService implementations in this simple Callable Future example.

1. Java Callable and Future Interfaces

1.1. Callable

In Java concurrency, Callable represents a task that returns a result. Executors 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.

Callable interface has the call() method. In this method, we have to implement the logic of a task. The Callable interface is a parameterized interface, meaning we have to indicate the type of data the call() method will return.

@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;
}

2.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 been completed, blocking if necessary until it is ready.

The cancellation of a task is performed by the cancel() method. Once a computation has been completed, the computation cannot be canceled.

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. Java Callable Future Example

In this example, we are executing a task that returns its name when it’s completed. We will use ExecutorService to execute this task and print its name in main thread after it has been completed.

The Future.get() is used for blocking the main thread execution until the corresponding task submitted to the executor is not completed. It can, optionally, take a timeout period after which it will unblock with a TimeOutException.

import java.time.LocalDateTime;
import java.util.concurrent.*;

public class CallableFutureExample {
  public static void main(String[] args) throws ExecutionException,
      InterruptedException, TimeoutException {

    ExecutorService executor = Executors.newFixedThreadPool(1);
    Future<String> future = executor.submit(new Work("Demo-Task"));

    String completedThread = future.get(10, TimeUnit.SECONDS);

    System.out.println("Thread completed : " + completedThread);
  }
}

class Work implements Callable<String> {
  private final String name;

  public Work(String name) {this.name = name;}

  @Override
  public String call() {
    System.out.println("Task [" + name + "] executed on : " + LocalDateTime.now().toString());
    return name;
  }
}

Program output.

Task [Demo-Task] executed on : 2022-08-07T15:57:33.372000500
Thread completed : Demo-Task

Here we sent a Callable object to be executed in an executor using the submit() method. This method receives a Callable object as a parameter and returns a Future object that we can use with two main objectives –

  1. We can control the status of the task – we can cancel the task and check if it has finished. For this purpose, we can use the isDone() method to check if the tasks had finished.
  2. We can get the result returned by the call() method. For this purpose, we have used the 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, this method throws an ExecutionException exception.

3. Conclusion

In this tutorial, we learned the basics of the Callable and Future interfaces and how to execute callable tasks with ExecutorService. We learned to control the execution using the isDone(), cancel() and get() methods.

Happy Learning !!

Leave a Reply

14 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial