Google

Nov 25, 2013

Java FutureTask example

Java 5 introduced the concurrent package for more efficient multi-threading. The executor framework and callable/Future interfaces were covered in the post entitled

Java 5 Executor framework

Q. What is the difference between Future and FutureTask in asynchronous processing?
A. Future is the interface and FutureTask is the base implementation of the Future with methods to start and cancel a computation. The FutureTask provides asynchronous computation with methods to start and cancel a computation, query to see if the computation is complete, and retrieve the result of the computation. The result can only be retrieved when the computation has completed. The get method will block if the computation has not yet completed. Once the computation has completed, the computation cannot be restarted or cancelled.

Here is an example with 2 tasks. One is an internal short task that takes ~1 second. The second task is an external long running task taking 4 ~ 10 seconds. It is imperative that long running tasks need to have proper processing timeouts.


 
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class FutureTaskExample {

 // inner class
 static class InternalProcess implements Callable&t;Integer> {

  @Override
  public Integer call() throws Exception {
   
   // just to simulate short internal process
   TimeUnit.SECONDS.sleep(1);
   return 2;
  }

 }

 // inner class
 static class ExternalProcess implements Callable&t;Integer> {

  @Override
  public Integer call() throws Exception {
   // just to simulate long running external process
   TimeUnit.SECONDS.sleep(15);
   return 12;
  }
 }

 public static void main(String[] args) {
  InternalProcess callable1 = new InternalProcess();
  ExternalProcess callable2 = new ExternalProcess();

  FutureTask&t;Integer> futureTask1 = new FutureTask&t;Integer>(callable1);
  FutureTask&t;Integer> futureTask2 = new FutureTask&t;Integer>(callable2);

  // create a fixed thread pool with 2 threads
  ExecutorService executor = Executors.newFixedThreadPool(2);
  // add future tasks to the pool
  executor.execute(futureTask1);
  executor.execute(futureTask2);

  while (true) {
   try {
    if (futureTask1.isDone() && futureTask2.isDone()) {
     System.out.println("Shutting down the executor.");
     // shut down executor service
     executor.shutdown();
     return;
    }

    //if not done do it once
    if (!futureTask1.isDone()) {
     // wait indefinitely for future task to complete
     System.out.println("Task1 output = "
       + futureTask1.get());
    }

    System.out.println("Waiting for FutureTask2 to complete");
    //try the external task with the timeout of 5 seconds
    Integer result = futureTask2.get(5, TimeUnit.SECONDS);
    if (result != null) {
     System.out.println("Task2 output = " + result);
    }
   } catch (InterruptedException ie) {
    ie.printStackTrace();
   } catch (TimeoutException e) {
    // do nothing as we want to process it asynchronously
    // if you want to time out then uncomment 2 lines
    
    //System.out.println("Cancelling Task2 due to timeout");
    //futureTask2.cancel(true); // true means interrupt
   } catch (ExecutionException e) {
    e.printStackTrace();
   }
  }
 }

}




The output is

 
Task1 output = 2
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Task2 output = 12
Shutting down the executor.


If you re-run it by uncommenting the last 2 lines in the TimeoutException catch block, you will get task2 cancelled.

 
Task1 output = 2
Waiting for FutureTask2 to complete
Cancelling Task2 due to timeout
Shutting down the executor.

Labels:

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home