java.util.concurrent.FutureTask Example
In this example we shall show you how to make FutureTask
, FutureTask
is an implementation of Future
which offers a very elegant way to implement parallel execution of tasks in Java where a big task can be split into small chunks and if each of those chunks can be executed in parallel, it can result in better response times and throughput.
We can explicitly instantiate a FutureTask
for a given Runnable
or Callable
. A FutureTask
can be submitted to an Executor for execution as FutureTask
implements Runnable
. FutureTask
can also be executed directly by calling its run()
method. Once a FutureTask
enters the completed state, it stays in that state forever.
1. Callable vs Runnable
FutureTask
constructors can accept either Runnable
or Callable
. Though both Runnable
and Callable
interface are designed to represent task, which can be executed by any thread, there is some significant difference between them.
- A
Callable
needs to implementcall()
method while aRunnable
needs to implementrun()
method. - A
Callable
can return a value but aRunnable
cannot. - A
Callable
can throwchecked exception
but aRunnable
cannot.
Now, let’s see an example which show how can get benefits from running a huge heavy tasks using FutureTask
.
2. Example
Calculater.java:
package com.jcg; /** * @author ashraf * */ public class Calculater { /** * Calculate number of divisible. * * Returns the amount of numbers that can be divided by the divisor without remainder. * * @param first the first * @param last the last * @param divisor the divisor * @return the int */ public static long calculateNumberOfDivisible(long first, long last, long divisor) { long amount = 0; for (long i = first; i <= last; i++) { if (i % divisor == 0) { amount++; } } return amount; } }
Calculater.java
contains calculateNumberOfDivisible()
which checks how many numbers in a given range can be divided by a certain divisor without remainder.
CallableCalculater.java:
package com.jcg; import java.util.concurrent.Callable; /** * @author ashraf * */ public class CallableCalculater implements Callable { private long first; private long last; private long divisor; /** * Instantiates a new callable calculater. * * @param first the first * @param last the last * @param divisor the divisor */ public CallableCalculater(long first, long last, long divisor) { this.first = first; this.last = last; this.divisor = divisor; } @Override public Long call() throws Exception { return Calculater.calculateNumberOfDivisible(first, last, divisor); } }
CallableCalculater.java
is wrapping the calculateNumberOfDivisible()
of Calculater.java
in a Callable
task to be given to our FutureTask
later on.
FutureTaskDemo.java:
package com.jcg; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; /** * @author ashraf * */ public class FutureTaskDemo { // Maximum number to check public static final long MAX_NUMBER = 3000000000l; // DIVISOR to be used in calculation private static final long DIVISOR = 3; /** * @param args * @throws ExecutionException * @throws InterruptedException */ public static void main(String[] args) { // Sequential execution System.out.println("Starting sequential execution ...."); long timeStart = System.currentTimeMillis(); long result = Calculater.calculateNumberOfDivisible(0, MAX_NUMBER, DIVISOR); long timeEnd = System.currentTimeMillis(); long timeNeeded = timeEnd - timeStart; System.out.println("Result : " + result + " calculated in " + timeNeeded + " ms"); // Parallel execution System.out.println("Starting parallel execution ...."); long timeStartFuture = System.currentTimeMillis(); long resultFuture = 0; // Create a new ExecutorService with 2 thread to execute and store the Futures ExecutorService executor = Executors.newFixedThreadPool(2); List<FutureTask> taskList = new ArrayList<FutureTask>(); // Start thread for the first half of the numbers FutureTask futureTask_1 = new FutureTask(new CallableCalculater(0, MAX_NUMBER / 2, DIVISOR)); taskList.add(futureTask_1); executor.execute(futureTask_1); // Start thread for the second half of the numbers FutureTask futureTask_2 = new FutureTask(new CallableCalculater(MAX_NUMBER / 2 + 1, MAX_NUMBER, 3)); taskList.add(futureTask_2); executor.execute(futureTask_2); // Wait until all results are available and combine them at the same time for (FutureTask futureTask : taskList) { try { resultFuture += futureTask.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } // Shutdown the ExecutorService executor.shutdown(); long timeEndFuture = System.currentTimeMillis(); long timeNeededFuture = timeEndFuture - timeStartFuture; System.out.println("Result (Future): " + resultFuture + " calculated in " + timeNeededFuture + " ms"); } }
FutureTaskDemo.java
is our main class which is running our Calculater.java
in two different manner, the first one is the sequential execution where there will be only one thread which executes our logic and the second one is the parallel execution using a FutureTask
where there will be multiple tasks which execute our logic. Also, we will print the consumed time in both of them to see the difference.
The sequential execution doesn’t need more explanation. So, we will deep into the parallel one to get more details.
First of all we create an Executor
with a fixed thread pool from Executors framework which will be used to start the FutureTask
later on, as well as a list in which we will be storing these tasks.
ExecutorService executor = Executors.newFixedThreadPool(2); List<FutureTask> taskList = new ArrayList<FutureTask>();
Then, we will create two FutureTask
which will be added to the list and executed using our Executor
.
FutureTask futureTask_1 = new FutureTask(new CallableCalculater(0, MAX_NUMBER / 2, DIVISOR)); taskList.add(futureTask_1); executor.execute(futureTask_1); FutureTask futureTask_2 = new FutureTask(new CallableCalculater(MAX_NUMBER / 2 + 1, MAX_NUMBER, 3)); taskList.add(futureTask_2); executor.execute(futureTask_2);
After that, we will go for the “blocking call” using the
method of our get()
FutureTask
objects in a loop. This will only return once the processing is finished, thus in this example the first call will probably wait longer and when we reach the second object processing, it will be done already and the result is returned. Then the results are simply aggregated and returned at the end.
for (FutureTask futureTask : taskList) { try { resultFuture += futureTask.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }
Finally, When you are done using the ExecutorService
you should shut it down, so the threads do not keep running.
executor.shutdown();
For instance, if your application is started via a main()
method and your main thread exits your application, the application will keep running if you have an active ExecutorService
in your application. The active threads inside this ExecutorService
prevents the JVM from shutting down.
To terminate the threads inside the ExecutorService
you call its shutdown()
method. The ExecutorService
will not shut down immediately, but it will no longer accept new tasks, and once all threads have finished current tasks, the ExecutorService
shuts down. All tasks submitted to the ExecutorService
before shutdown()
is called, are executed.
If you want to shut down the ExecutorService
immediately, you can call the shutdownNow()
method. This will attempt to stop all executing tasks right away, and skips all submitted but non-processed tasks. There are no guarantees given about the executing tasks.
Output:
We can notice that the execution time of the method using FutureTask
is almost twice as fast as the purely sequential execution.
Starting sequential execution .... Result : 1000000001 calculated in 235817 ms Starting parallel execution .... Result (Future): 1000000001 calculated in 144028 ms
Download the Source Code of this example
This was an example of Java Concurrency FutureTask
.
You can download the full source code of this example here: FutureTaskExampleCode.zip