Sunday, September 17, 2023

How to use Callable and Future in Java? Example Tutorial

A callable interface was added in Java 5 to complement the existing Runnable interface, which is used to wrap a task and pass it to a Thread or thread pool for asynchronous execution. Callable actually represents an asynchronous computation, whose value is available via a Future object. All the code which needs to be executed asynchronously goes into the 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 types and can be used to wrap classes like Integer, String, or anything else.

When you pass a Callable to a thread pool, it chooses one thread and executes the Callable. It immediately returns a Future object which promises to hold the result of computation once done. You can then call the get() method of Future, which will return the result of computation or block if the Computation is not complete.

If you don't like indefinite blocking then you can also use an overloaded get() method with a timeout. The future also allows you to cancel the task if it's not started or interrupt if it started. We will see, how we can calculate factorial of large numbers using Callable and Future in Java.

And, if you are serious about mastering Java multi-threading and concurrency then I also suggest you take a look at the Java Multithreading, Concurrency, and Performance Optimization course by Michael Pogrebinsky on Udemy. It's an advanced course to become an expert in Multithreading, concurrency, and Parallel programming in Java with a strong emphasis on high performance




Difference between Callable vs Runnable in Java

Many of you would be familiar with the Runnable interface, one of the most popular ways to use thread in Java, but you would be happy to know that Runnable is not the only way to create a task that can be executed by parallel threads.

You can also use a Callable interface to do the same. The main difference between Runnable and Callable is that Runnable cannot return any value back to the caller but Callable can return value. 

Another difference is that call() method from Callable can also throw a checked exception which was not possible by the run() method of the Runnable interface. See here to learn more about the difference between Runnable and Callable in Java.

BTW, if you are serious about mastering the concurrency API of Java, I suggest you also take a look at one of the best books on the subject, Java Concurrency in Practice by Brian Goetz. It is one of the books I keep refer whenever I have a doubt or want to refresh my knowledge.


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 a thread pool, Callable and Future, you don't need to wait for tasks to be completed, you can move on with other tasks and come back to check whether the task is completed or not. 

If the task is finished then just get the result by calling the get() method, but remember it's a blocking call, so it will block if the 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 the 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 the 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 the first Future object it's blocked until the calculation is done, that's why you will see the fifth line printing after some time.

For next two lines are also the same story because when you call the get() method it will block until the result is available. BTW, you don't need to block, you can even use the isDone() method to check if the calculation is completed or not before calling the get method.




Important points about Callable and Future in Java

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

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

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

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

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

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

Callable and Future Example in Java


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


Other Java Multithreading and Concurrency tutorials you may like
  • What is happens-before in Java concurrency? (answer)
  • How to use Future and FutureTask class in Java? (solution)
  • Difference between volatile, atomic, and synchronized in Java (answer)
  • How to use a CyclicBarrier class in Java? (example)
  • 50 Java Thread Questions for Senior and Experienced Programmers (questions)
  • How to use the CountDownLatch utility in Java? (example)
  • How to use Semaphore class in Java? (code sample)
  • How to use the Lock interface in multi-threaded programming? (code sample)
  • How to use Thread pool Executor in Java? (example)
  • Difference between CyclicBarrier and CountDownLatch in Java? (answer)
  • how to do inter-thread communication using wait and notify? (solution)
  • How to use ThreadLocal variables in Java? (example)
  • Top 5 Concurrent Collection classes from Java 5 and Java 6 (read here)
  • 10 Examples of ConcurrentHahsMap in Java (examples)
  • 10 Multi-threading and Concurrency Best Practices for Java Programmers (best practices)

Thanks for reading this article so far. If you like this Java Callable and Future example then please share it with your friends and colleagues. If you have any questions or feedback then please drop a note. 

P.S. - If you are new to Java Programming language and need a free course to learn essential Java thread concepts then I highly suggest you join this free Java Multithreading course for beginners. This is a free Udemy course to learn Java Multithreading from scratch. 

2 comments :

Arun said...

In above example,

Future should be declared with type parameter
Future result10 = es.submit..... and so on.

Otherwise get() would return an Object type and so the compilation errors will be shown at
long factorialof10 = result10.get();

-Arun

Shiva said...

Thanks!!
Very helpful for me :)

Post a Comment