FutureTask

java.util.concurrent.FutureTask Example

In this example we shall show you how to make FutureTaskFutureTask 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 RunnableFutureTask 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.

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 get() method of our 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.

Download
You can download the full source code of this example here: FutureTaskExampleCode.zip

Ashraf Sarhan

Ashraf Sarhan is a passionate software engineer, an open source enthusiast, has a Bsc. degree in Computer and Information Systems from Alexandria University. He is experienced in building large, scalable and distributed enterprise applications/service in multiple domains. He also has a keen interest in JavaEE, SOA, Agile and Big Data technologies.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button