Monday, 20 July 2015

How to use Callable and Future in Java? Example

Callable interface was added in Java 5 to complement existing Runnable interface, which is used to wrap a task and pass it to a Thread or thread pool for asynchronous execution. Callable actually represent an asynchronous computation, whose value is available via Future object. All the code which needs to be executed asynchronously goes into call() method. Callable is also a single abstract method type (SAM type), so it can be used along with lambda expression on Java 8. Both Callable and Future are parametric type and can be used to wrap classes like Integer, String or anything else. When you pass a Callable to thread pool, it choose one thread and execute the Callable. It immediately return a Future object which promises to hold result of computation once done. You can then call get() method of Future, which will return result of computation or block if Computation is not complete. If you don't like indefinite blocking then you can also use overloaded get() method with timeout. Future also allows you to cancel the task if its not started or interrupt if its started. We will see, how we can calculate factorial of large number using Callable and Future in Java. BTW, if you are serious about mastering concurrency API of Java, I suggest you to also take a look at one of the best book on the subject, Java Concurrency in Practice by Brian Goetz. It is one of the book I keep refer whenever I have a doubt or want to refresh my knowledge.



Callable vs Runnable

Many of you would be familiar with Runnable interface, one of the most popular way to use thread in Java, but you would be happy to know that Runnable is not the only way to create a task which can be executed by parallel threads. You can also use Callable interface to do the same. Main difference between Runnable and Callable is that Runnable cannot return any value back to caller but Callable can return value. Another difference is that call() method from Callable can also throw checked exception which was not possible by run() method of Runnable interface. See here to learn more about difference between Runnable and Callable in Java.

Runnable vs Callable vs Future in Java


Callable and Future Example in Java

Here is our complete Java program to demonstrate how you can use Callable and Future together to implement asynchronous processing  in Java. Once you started using thread pool, Callable and Future, you don't need to wait for task to be completed, you can move on with other task and comeback to check whether task is completed or not. If task is finished then just get the result by calling get() method, but remember its a blocking call, so it will block if task is not finished.


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;

/**
 * Simple Java program to demonstrate how to use Callable and Future class in
 * Java. You can use FutureTask for asynchronous processing.
 * 
 * @author WINDOWS 8
 *
 */
public class HelloWorldApp {

    public static void main(String... args) throws InterruptedException, ExecutionException {
       
       // creating thread pool to execute task which implements Callable
       ExecutorService es = Executors.newSingleThreadExecutor();
       
       System.out.println("submitted callable task to calculate factorial of 10");
       Future result10 = es.submit(new FactorialCalculator(10));
       
       System.out.println("submitted callable task to calculate factorial of 15");
       Future result15 = es.submit(new FactorialCalculator(15));
       
       System.out.println("submitted callable task to calculate factorial of 20");
       Future result20 = es.submit(new FactorialCalculator(20));
       
       System.out.println("Calling get method of Future to fetch result of factorial 10");
       long factorialof10 = result10.get();
       System.out.println("factorial of 10 is : " + factorialof10);
       
       System.out.println("Calling get method of Future to get result of factorial 15");
       long factorialof15 = result15.get();
       System.out.println("factorial of 15 is : " + factorialof15);
       
       System.out.println("Calling get method of Future to get result of factorial 20");
       long factorialof20 = result20.get();
       System.out.println("factorial of 20 is : " + factorialof20);

    }

}

class FactorialCalculator implements Callable<Long> {
    private int number;
    
    public FactorialCalculator(int number){
        this.number = number;
    }

    @Override
    public Long call() throws Exception {
        return factorial(number);
    }

    private long factorial(int n) throws InterruptedException {
        long result = 1;
        while (n != 0) {
            result = n * result;
            n = n - 1;
            Thread.sleep(100);
        }

        return result;
    }

}

Output
submitted callable task to calculate factorial of 10
submitted callable task to calculate factorial of 15
submitted callable task to calculate factorial of 20
Calling get method of Future to fetch result of factorial 10
factorial of 10 is : 3628800
Calling get method of Future to get result of factorial 15
factorial of 15 is : 1307674368000
Calling get method of Future to get result of factorial 20
factorial of 20 is : 2432902008176640000


When you run this program, you will see that first 4 lines will be printed immediately because submit() is a non blocking method, it just takes a task and returns a Future object, it doesn't wait until task is completed. That's why you see that all three tasks to calculate factorials are submitted immediately, but they are not done yet. When our code calls get() on first Future object its blocked until the calculation is done, that's why you will see the fifth line printing after sometime. For next two lines also same story because when you call get() method it will block until result is available. BTW, you don't need to block, you can even use isDone() method to check if calculation is completed or not before calling get method.


Important points about Callable and Future

1) Callable is a SAM type interface, so it can be used in lambda expression.

2) Callable has just one method call() which holds all the code needs to executed asynchronously.

3) In Runnable interface, there was no way to return the result of computation or throw checked exception but with Callable you can both return a value and can throw checked exception.

4) You can use get() method of Future to retrieve result once computation is done. You can check if computation is finished or not by using isDone() method.

5) You can cancel the computation by using Future.cancel() method.

6) get() is a blocking call and it blocks until computation is completed.

Callable and Future Example in Java


That's all about how to use Callable and Future object in Java. You can wrap asynchronous computation inside call() method and pass it to a single thread or thread pool for execution. you don't need to wait until execution complete, your thread can carry on with future object returned by call method. Once computation is done you can query the future object and get the result back.

Recommended resource for further learning
  • Java tutorial on  Concurrency Package (documentation)
  • Java Concurrency in Practice by Brian Goetz (the book)
  • The Art of Multiprocessor Programming by Maurice Herlihy  (the book)

No comments:

Post a Comment