In this tutorial, we will understand Java Callable and Future interfaces and how to use them along with examples. Both these interfaces are part of the java.util.concurrent
package. We can use the Callable and Future interfaces to execute concurrent tasks and retrieve a single result after the task execution.
Table of Contents
Java Callable interface
The Callable interface in Java has a call()
method that executes asynchronous tasks. It returns a result that we can access using the Future interface. In case the task fails, the call()
method throws an Exception. The call()
method contains the implementation of the actual task. Below is the syntax of the call()
method.
public Object call() throws Exception;
Implementing the Callable interface
To override the call()
method that contains the task implementation, we need to create a class that overrides the Callable interface. Below is an example of implementing the Callable interface. This class contains the call()
method that calculates the square of a number and returns the result.
import java.util.concurrent.Callable; class Square implements Callable { int a = 5; @Override public Integer call() throws Exception { return a*a; } }
Java Future interface
The Java Future interface helps to retrieve the result that is returned as an outcome of the call()
method. In other words, the Future object stores the result of a task. The interface has several methods to perform different operations.
Future interface methods
Get Result: get() method
The get()
method of the Java Future interface helps to retrieve the result of the task executed using the call()
method. It returns an object of the specific types that represents the result. If we invoke the get()
method before the task completion, then it blocks until it obtains the result. In case we pass parameter to the get()
method, then it waits for the specified amount of time to obtain the result. When timeout occurs, it throws TimeOutException
.
Object response = future.get(); Object response = future.get(2000, TimeUnit.MILLISECONDS);
Cancel task: cancel() method
We can cancel the asynchronous task execution using the cancel()
method of the Future interface in Java. If the task is not implemented, then calling the cancel()
method will have no effect.
future.cancel();
Verify taks completion: isDone() method
We can check if the asynchronous task execution is complete using the isDone()
method.
Boolean bVal = future.isDone();
Verify task cancellation: isCancelled() method
To check if the task is actually canceled, we can use the isCancelled()
method.
Boolean bVal = future.isCancelled();
Example: Java Callable Future interface
Below is an example of how to use Callable and Future interface in Java to execute multiple tasks and obtain a result. Here, we generate square of random numbers between 0 and 10. The call() method contains the implementation of calculating a square of a number. Using the FutureTask class, we can create the number of tasks we want to execute and then create a constructor using the Callable instance. Using the
import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; class Square implements Callable { int num; Square(int num) { this.num = num; } @Override public Object call() throws Exception { int result = num*num; return result; } } public class CallableDemo { public static void main(String[] args) throws InterruptedException, ExecutionException { FutureTask[] sqvalue = new FutureTask[4]; for(int i=0;i<2;i++) { Random value = new Random(); Integer val = value.nextInt(10); Callable c = new Square(val); sqvalue[i] = new FutureTask(c); Thread th = new Thread(sqvalue[i]); th.start(); } for(int i=0;i<2;i++) { System.out.println(sqvalue[i].get()); } } }
9 64
We can also use the ThreadPool of the ExecutorService to execute multiple tasks as in the below example. The ExecutorService has a submit()
method that helps to invoke the call()
method of the Callable interface.
import java.util.ArrayList; import java.util.List; import java.util.Random; 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.FutureTask; class Square implements Callable { int num; Square(int num) { this.num = num; } @Override public Object call() throws Exception { int result = num*num; System.out.println("Square of " + num + " is: " + result); return result; } } public class CallableDemo { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService exec = Executors.newFixedThreadPool(5); List<Future<Integer>> l = new ArrayList<Future<Integer>>(); Random value = new Random(); for(int i=0;i<5;i++) { Integer val = value.nextInt(10); Square s = new Square(val); Future<Integer> response = exec.submit(s); l.add(response); } for(Future<Integer> f : l) { try { System.out.println("Result from future is: " + f.get()); System.out.println("Task completed: " + f.isDone()); } catch(Exception e) { e.printStackTrace(); } } exec.shutdown(); } }
Square of 8 is: 64 Square of 1 is: 1 Square of 0 is: 0 Square of 9 is: 81 Square of 6 is: 36 Result from future is: 64 Task completed: true Result from future is: 36 Task completed: true Result from future is: 1 Task completed: true Result from future is: 0 Task completed: true Result from future is: 81 Task completed: true
Callable vs Runnable
Though there are similarities between Callable and Runnable interfaces, below are the few differences between them.
Callable | Runnable |
---|---|
The Callable interface has a call() method to execute task | The Runnable interface has a run() method to execute task |
It returns a result | It does not return any result |
Ideally for small task that return result | Ideal for long running concurrent execution |
The call() method can throw an exception | The run() method cannot throw an exception |