Future Interface in Java

In this article, we will learn the methods of Future interface with examples.

Future Interface Methods


  • boolean cancel(boolean mayInterruptIfRunning)Attempts to cancel execution of this task.
  • V get()Waits if necessary for the computation to complete, and then retrieves its result.
  • V get(long timeout, TimeUnit unit)Waits if necessary for at most the given time for the computation to complete, and then retrieves its result, if available.
  • boolean isCancelled() Returns true if this task was canceled before it completed normally.
  • boolean isDone()Returns true if this task completed.

Future Interface Overview

Future is a generic interface that represents the value that will be returned by a Callable object. Because this value is obtained at some future time, the name Future is appropriate.
Future is defined like this:
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;
}
Here, V specifies the type of the result. To obtain the returned value, you will call Future’s get( ) method, which has these two forms:
V get( ) throws InterruptedException, ExecutionException
V get(long wait, TimeUnit tu) throws InterruptedException, ExecutionException, TimeoutException
The first form waits for the result indefinitely. The second form allows you to specify a timeout period in wait.

Executing Callable tasks using ExecutorService and obtaining the result using Future

Threads that return values are better implemented in Java using Callable and Future. Use the Executors Framework to run a Callable task.
Following is a simple example of Future and Callable. In this example, we are creating five tasks using a callable interface and each task job is to sum numbers given for each task and the result is stored in a Future interface.
Let's first create task - SumNumbers.
class SumNumbers implements Callable<Integer> {
     private int n;
 
     public SumNumbers(int n) {
          this.n = n;
     }
 
     public Integer call() {
         int sum = 0;
         for (int i = 1; i <= n; i++) {
   
             sum += i;
             try {
                 Thread.sleep(200);
             } catch (InterruptedException e) {
                   e.printStackTrace();
             }
          }
         System.out.println("[" + Thread.currentThread().getName() + "] of sum " + sum);
         return sum;
     }
}
Let's create and submit Task using ExecutorService.submit() method returns immediately and gives you a Future. Once you have obtained a future, you can execute other tasks in parallel while your submitted task is executing, and then use future.get() method to retrieve the result of the future.
public class ReturnValuesUsingCallable {
 
 public static void main(String[] args) throws InterruptedException, ExecutionException {
  
      System.out.println("Thread main started");
  
      ExecutorService executorService = Executors.newSingleThreadExecutor();
      Future<Integer> returnedValues = executorService.submit(new SumNumbers(10));
      System.out.println("Result of Future object:: " + returnedValues.get());
      executorService.shutdown();
  
      System.out.println("Thread main finished");
   }
}
Output:
Thread main started
[pool-1-thread-1] of sum 55
Result of Future object:: 55
Thread main finished
Let's simplify above example using Java 8 Lambda Expressions:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ReturnValuesUsingCallable {
 
 public static void main(String[] args) throws InterruptedException, ExecutionException {
  
      System.out.println("Thread main started");
  
      ExecutorService executorService = Executors.newSingleThreadExecutor();
      Future<Integer> returnedValues = executorService.submit(() -> {
          int sum = 0;
          for (int i = 1; i <= 5; i++) {
    
               sum += i;
               try {
                    Thread.sleep(200);
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
          }
          System.out.println("[" + Thread.currentThread().getName() + "] of sum " + sum);
          return sum;
     });
  
      System.out.println("Result of Future object:: " + returnedValues.get());
      executorService.shutdown();
  
      System.out.println("Thread main finished");
   }
}
Output:
Thread main started
[pool-1-thread-1] of sum 15
Result of Future object:: 15
Thread main finished
Note that, the get() method blocks until the task is completed. The Future API also provides an isDone() method to check whether the task is completed or not.

isDone() - Check Completion of Task

Returns true if this task completed. Completion may be due to normal termination, an exception, or cancellation -- in all of these cases, this method will return true.
public class ReturnValuesUsingCallable {
 
    public static void main(String[] args) throws InterruptedException, ExecutionException {
  
        System.out.println("Thread main started");
  
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future<Integer> returnedValues = executorService.submit(() -> {
             int sum = 0;
             for (int i = 1; i <= 5; i++) {
    
                sum += i;
             try {
                 Thread.sleep(200);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
            System.out.println("[" + Thread.currentThread().getName() + "] of sum " + sum);
            return sum;
       });
  
        while(!returnedValues.isDone()) {
             System.out.println("Task is still not done...");
             Thread.sleep(200);
         }
   
         System.out.println("Result of Future object:: " + returnedValues.get());
         executorService.shutdown();
  
         System.out.println("Thread main finished");
    }
}
Output:
Thread main started
Task is still not done...
Task is still not done...
Task is still not done...
Task is still not done...
Task is still not done...
Task is still not done...
[pool-1-thread-1] of sum 15
Result of Future object:: 15
Thread main finished

cancel() - Canceling a Future

You can cancel a future using Future.cancel() method. It attempts to cancel the execution of the task and returns true if it is canceled successfully, otherwise, it returns false.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ReturnValuesUsingCallable {

 public static void main(String[] args) {

  System.out.println("Thread main started");

  long startTime = System.nanoTime();

  ExecutorService executorService = Executors.newSingleThreadExecutor();
  Future<Integer> returnedValues = executorService.submit(() -> {
   int sum = 0;
   for (int i = 1; i <= 5; i++) {
    sum += i;
   }
   System.out.println("[" + Thread.currentThread().getName() + "] of sum " + sum);
   return sum;
  });

  while (!returnedValues.isDone()) {
   System.out.println("Task is still not done...");
   returnedValues.cancel(true);
  }

  try {
   System.out.println("Result of Future object:: " + returnedValues.get());
  } catch (InterruptedException | ExecutionException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  executorService.shutdown();

  System.out.println("Thread main finished");
 }
}
Output:
Thread main started
Task is still not done...
[pool-1-thread-1] of sum 15
Exception in thread "main" java.util.concurrent.CancellationException
 at java.util.concurrent.FutureTask.report(FutureTask.java:121)
 at java.util.concurrent.FutureTask.get(FutureTask.java:192)
 at com.javaguides.javamultithreading.concurrency.ReturnValuesUsingCallable
        .main(ReturnValuesUsingCallable.java:32)

get(100, TimeUnit.SECONDS) - Adding Timeouts

The future.get() method blocks and waits for the task to complete. If you call an API from a remote service in the callable task and the remote service is down, then future.get() will block forever, which will make the application unresponsive.
To guard against this fact, you can add a timeout in the get() method -
future.get(1, TimeUnit.SECONDS);
The future.get() method will throw a TimeoutException if the task is not completed within the specified time.

invokeAll() Method

Submit multiple tasks and wait for all of them to complete.
You can execute multiple tasks by passing a collection of Callables to the invokeAll() method. The invokeAll() returns a list of Futures. Any call to future.get() will block until all the Futures are complete.
import java.util.Arrays;
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;

public class ReturnValuesUsingCallable {
 
 public static void main(String[] args) throws InterruptedException, ExecutionException {
  
  System.out.println("Thread main started");
  
  ExecutorService executorService = Executors.newFixedThreadPool(5);
  List<Future<Integer>> returnedValues = executorService.invokeAll(Arrays.asList(
    new SumNumbers(50), 
    new SumNumbers(40),
    new SumNumbers(30),
    new SumNumbers(20),
    new SumNumbers(10)));
  
  for (Future<Integer> value : returnedValues) {
   System.out.println(value.get());
  }
  
  executorService.shutdown();
  
  System.out.println("Thread main finished");
 }
}

class SumNumbers implements Callable<Integer> {
 private int n;
 
 public SumNumbers(int n) {
  this.n = n;
 }
 
 public Integer call() {
  int sum = 0;
  for (int i = 1; i <= n; i++) {
   sum += i;
   try {
    Thread.sleep(200);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  System.out.println("[" + Thread.currentThread().getName() + "] Sum " + sum);
  return sum;
 }
}
Output:
Thread main started
[pool-1-thread-5] Sum 55
[pool-1-thread-4] Sum 210
[pool-1-thread-3] Sum 465
[pool-1-thread-2] Sum 820
[pool-1-thread-1] Sum 1275
1275
820
465
210
55
Thread main finished

invokeAny() Method

Executes the given tasks, returning the result of one that has completed successfully (i.e., without throwing an exception), if any do. Upon normal or exceptional return, tasks that have not completed are canceled. The results of this method are undefined if the given collection is modified while this operation is in progress.
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ReturnValuesUsingCallable {
 
 public static void main(String[] args) throws InterruptedException, ExecutionException {
  
  System.out.println("Thread main started");
  
  ExecutorService executorService = Executors.newFixedThreadPool(5);
  Integer returnedValues = executorService.invokeAny(Arrays.asList(
    new SumNumbers(50), 
    new SumNumbers(40),
    new SumNumbers(30),
    new SumNumbers(20),
    new SumNumbers(10)));
  
  System.out.println(returnedValues);
  
  executorService.shutdown();
  
  System.out.println("Thread main finished");
 }
}

class SumNumbers implements Callable<Integer> {
 private int n;
 
 public SumNumbers(int n) {
  this.n = n;
 }
 
 public Integer call() {
  int sum = 0;
  for (int i = 1; i <= n; i++) {
   sum += i;
  }
  System.out.println("[" + Thread.currentThread().getName() + "] Sum " + sum);
  return sum;
 }
}
Output:
Thread main started
[pool-1-thread-1] Sum 1275
1275
Thread main finished

Free Spring Boot Tutorial | Full In-depth Course | Learn Spring Boot in 10 Hours


Watch this course on YouTube at Spring Boot Tutorial | Fee 10 Hours Full Course

Comments