Saturday, September 16, 2023

How to use Future and FutureTask in Java Concurrency with Example

Future and FutureTask in Java allows you to write asynchronous code. The Future is a general concurrency abstraction, also known as a promise, which promises to return a result in the future. In asynchronous programming, the main thread doesn't wait for any task to be finished, rather it hands over the task to workers and moves on. One way of asynchronous processing is by using callback methods. The Future class in Java is another way to write asynchronous code.


By using Future and FutureTask, you can write a method that does long computation but returns immediately. Those methods, instead of returning a result, return a Future object. You can later get the result by calling the Future.get() method, which will return an object of type T, where T is what the Future object is holding.

One example of the Future is the submit() method of ExecutorService, which immediately returns a Future object. By the way, Future and FutureTask are available in java.util.concurrent package from Java 1.5. Also, Future is an interface and FutureTask is an implementation or RunnableFuture, which can be used as a Runnable interface, thus, it can be passed to ExecutorService.

In this Java concurrency tutorial, we will learn how to use Future and FutureTask in Java. Btw, 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 Pogrebinsy 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.



Future and FutureTask Example - Java

One of the simplest examples of using the Future is working with Thread pools. When you submit a long-running task to ExecutorService, it returns a Future object immediately. This Future object can be used to query task completion and getting the result of the computation.

In our sample Java program, we have created a FactorialCalculator task, which wraps the calculation of factorial under the Callable interface's call() method.

When we submit this task with the job of calculating the factorial of a huge number like 100000, ExecutorService returns a Future object, which holds long value, the return type of call method in our case. Later, we check whether the task is completed or not using the isDone() method.

From the output, you can see that the main thread returns immediately. Since we have used the get() method once the task is completed, it doesn't block and return results immediately.

By the way, the Future object returned by the submit() method is also an instance of FutureTask.

Future and FutureTask Example in Java Concurrency




Sample Java Program to use Future and FutreTask

Here is our simple test program, which demonstrates how you can use these two classes to do asynchronous execution in Java. First, we have created a FutureTask which is nothing but a nested static class that implements a Callable interface.

In this method, we call our factorial method to calculate the factorial of a number. To make this method long-running, we have also introduced a small sleep duration. This will help you to better understand how Future works.

package test;

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.logging.Level;
import java.util.logging.Logger;

/**
 * Java program to show how to use Future in Java. Future allows to write
 * asynchronous code in Java, where Future promises result to be available in
 * future
 *
 * @author Javin
 */
public class FutureDemo {

    private static final ExecutorService threadpool 
              = Executors.newFixedThreadPool(3);

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

        FactorialCalculator task = new FactorialCalculator(10);
        System.out.println("Submitting Task ...");

        Future future = threadpool.submit(task);

        System.out.println("Task is submitted");

        while (!future.isDone()) {
            System.out.println("Task is not completed yet....");
            Thread.sleep(1); //sleep for 1 millisecond before checking again
        }

        System.out.println("Task is completed, let's check result");
        long factorial = future.get();
        System.out.println("Factorial of 1000000 is : " + factorial);

        threadpool.shutdown();
    }

    private static class FactorialCalculator implements Callable {

        private final int number;

        public FactorialCalculator(int number) {
            this.number = number;
        }

        @Override
        public Long call() {
            long output = 0;
            try {
                output =  factorial(number);
            } catch (InterruptedException ex) {
                Logger.getLogger(Test.class.getName())
                      .log(Level.SEVERE, null, ex);
            }
            
            return output;
        }

        private long factorial(int number) throws InterruptedException {
            if (number < 0) {
                throw new IllegalArgumentException("Number must be 
                                            greater than zero");
            }
            long result = 1;
            while (number > 0) {
                Thread.sleep(1); // adding delay for example
                result = result * number;
                number--;
            }
            return result;
        }
    }

}

Output
Submitting Task ...
Task is submitted
Task is not completed yet....
Task is not completed yet....
Task is not completed yet....
Task is completed, let's check result
Factorial of 1000000 is : 3628800

You can see that because of the sleep() method we have introduced in the factorial method, it took some time to finish and during that time isDone() method returned false. This is why you are seeing the output "Task is not completed yet". Once the task is completed the result is available as a Future object.

You can further see these Java multithreading and concurrency books to learn more about how to use concurrency classes in Java Program.

How to use Future and FutureTask in Java




Important points Future and FutureTask  in Java

Now we have learned how to use Future and FutureTask in the Java program. Let's revise some key points about the Future concept and FutureTask class in Java itself.

1. Future is a base interface and defines the abstraction of an object which promises results to be available in the future while FutureTask is an implementation of the Future interface.

2. Future is a parametric interface and type-safe written as Future<V>, where V denotes value.

3. Future provides get() method to get a result, which is blocking method and blocks until the result is available to Future.

4. Future interface also defines cancel() method to cancel the task.

5. isDone() and isCancelled() method is used to query Future task states. isDone() returns true if the task is completed and the result is available to Future. If you call the get() method, after isDone() returned true then it should return immediately. On the other hand, isCancelled() method returns true, if this task is canceled before its completion.


6. Future has four sub-interfaces, each with additional functionality e.g. Response, RunnableFuture, RunnableScheduledFuture, and ScheduledFuture. RunnableFuture also implements Runnable and successful finish of run() method cause completion of this Future.


7. FutureTask and SwingWorker are two well-known implementations of the Future interface. FutureTask also implements RunnableFuture interface, which means this can be used as Runnable and can be submitted to ExecutorService for execution.


8. Though most of the time ExecutorService creates FutureTask for you, i.e. when you submit() Callable or Runnable object. You can also create it manually.


9. FutureTask is normally used to wrap Runnable or Callable objects and submit them to ExecutorService for asynchronous execution.


That's all on How to use Future and FutureTask in Java. The understanding concept behind Future is very important for writing asynchronous code in Java. In simple words, the Future allows any method to return immediately, with the promise of the result being available in the future. By using this technique your main thread can do other things while waiting for certain tasks to be completed.

Other Java Concurrency Articles you may like
  • The Java Developer RoadMap (roadmap)
  • Difference between volatile, atomic, and synchronized in Java (answer)
  • 10 Java Multithreading and Concurrency Best Practices (article)
  • Top 50 Multithreading and Concurrency Questions in Java (questions)
  • 10 Courses to learn Java for Beginners (courses)
  • Difference between CyclicBarrier and CountDownLatch in Java? (answer)
  • How to avoid deadlock in Java? (answer)
  • Understanding the flow of data and code in Java program (answer)
  • Is Java Concurrency in Practice still valid (answer)
  • How to do inter-thread communication in Java using wait-notify? (answer)
  • 10 Tips to become a better Java Developer(tips)
  • 5 Essential Skills to Crack Java Interviews (skills)
  • How does Exchanger works in Java Multithreading (tutorial)
  • How does Thread works in Java? (answer)

Thanks for reading this article so far. If you like this Java Futures Tutorial and 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 the Java Programming and concurrency world and looking for some free courses to kick-start your Java programmer journey then you can also, check out this list of top 10 free Java courses for beginners to start with. It contains some free Java concurrency courses to start with basic thread concepts.  

And lastly, one question for you? Do you prefer synchronous programming or asynchronous multithreading using Future and Callable in Java? and Why?

11 comments :

SARAL SAXENA said...

Hi Javin,

pls check my blog on this , pls lem me know your feedback on this..

http://saralsaxena.blogspot.in/2015/01/parallel-processing_4.html

Anonymous said...

One of the drawback of using Future is that you either need to periodically check whether task is completed or not e.g. by using isDone() method or wait until task is completed by calling blocking get() method. There is no way to receive the notification when task is completed. This shortcoming is addressed in CompletableFture, which allows you to schedule some execution when the task is done. CompletableFuture class is introduced in Java 8 and you can perform some task when Future reaches completion stage.

Unknown said...

What is purpose of Thread pool here. I can have n number of threads from pool and program output does not vary at all.

javin paul said...

In this program, because there is only one call to calculate factorial, thread pool is not really tested. If you want to test thread pool, calculate factorial from multiple threads. Since we are using a fixed thread pool of size 3, you will notice your thread waiting longer as you calculate large factorials.

Unknown said...

thanks for your article.It helps me.

Unknown said...

How to submit three tasks to threadpool? Creating three instances of FactorialCalculator and then
Future future1 = threadpool.submit(task1);
Future future2 = threadpool.submit(task2);
Future future3 = threadpool.submit(task3);

Safwan Ahmad Siddiqi said...

Best part is that the factorial of 1000000 is 3628800.

Vivek Hingorani said...

That is the confusing part. Factorial of 10 is 3628800 and not of 1000000
Javin please correct the same

Guruprasad said...

I don't think we need a future.done check in this code. future.get() will wait till the execution is complete and display the result.

Prosenjit Das said...

future.get() will wait till the execution

javin paul said...

future.get() is blocking call as suggested by Prosenjit, if you want your application to not do anything till then you can call get() but done() is for asynchronous checking.

Post a Comment