e-Zest members share technology ideas to foster digital transformation.

The Executor Framework – Part III

Written by Madhura Oak | Feb 20, 2013 11:05:03 AM

In the Part II of Executor Framework blog post series, I had written about creating cancellable Runnable task and creating Runnable task with a timeout with the help of this framework. I had also written about two submit methods of ExecutorService, which are used to create asynchronous task.

In this blog post, I am writing about the following:

  1. Callable interface
  2. Creating Callable task
  3. Assigning a timeout to ExecutorService after shutdown.

Callable

The Callable interface is a part of Concurrency API. Like Runnable, this interface is used to define a task which will be executed by a thread. The Callable<T> interface overcomes the drawbacks of Runnable. It has a call() method which returns the result of type T.

The following are the two drawbacks of Runnable interface:

  1. The return type of run() method, which is used to define what a task should do when a thread runs it, is void. The thread executing Runnable cannot return a value directly after the execution of run() method is over. One way to return a value is to declare an instance variable and set it at the end of run() method. However, there is no way to find out whether the execution of run() method is over while trying to retrieve its value. So another instance variable is needed which tells whether the run() method execution is complete.
  2. The run() method cannot throw a checked exception. If the task has to throw a checked exception then it should catch it, wrap it within a RuntimeException and re-throw the latter which defies the purpose of checked exceptions.

An implementation of Callable interface which counts the sum of Integer numbers is given in Listing 1. The call method returns Integer result.

public class ComputeSum implements Callable<Integer> {
    private List<Integer> numbers;

    public void setNumbers(List<Integer> numbers) {
        this.numbers = numbers;
    }

    public Integer call() throws Exception {
        int sum = 0;
	for(Integer number : numbers) {
	    System.out.println("Adding number : " + number);
	    sum += number;
	}
	return sum;
    }
}

Listing 1. A Callable<Integer> implementation

Creating Callable task

The submit(Callable<T> task) method of ExecutorService allows submission of Callable task for asynchronous execution. The Future<T> is returned by this method which is used to obtain the result of execution.

Listing 2 shows a code which generates ten random numbers and uses the Callable implementation in Listing 1 to compute their sum. A single worker threaded ExecutorService is used to submit the task for execution. The get() method of Future is called to wait until the sum of numbers is obtained.

//Generate 10 random numbers in the range of 0 to 100
Random randomGenerator = new Random();
List<Integer> numbers = new ArrayList<Integer>();
for(int i=1; i<=10; i++) {
    numbers.add(randomGenerator.nextInt(100));
}

ExecutorService service = Executors.newSingleThreadExecutor();

//compute their sum
ComputeSum task = new ComputeSum();
task.setNumbers(numbers);
Future<Integer> future = service.submit(task);

//wait till the sum is computed
try {
    Integer sum = future.get();
    System.out.println("Sum = " + sum);
}
catch (InterruptedException e) {
    e.printStackTrace();
}
catch (ExecutionException e) {
    e.printStackTrace();
}

service.shutdown();

Listing 2. Code to create Callable task

Assign a timeout to ExecutorService after shutdown

In the Part I of this blog post series, I had written about the shutdown() and shutdownNow() methods used to stop the ExecutorService. The shutdown() method waits until execution of all active tasks is completed. The maximum time period for which an ExecutorService should wait for the active tasks to complete after shutdown() is called, can be assigned by calling its awaitTermination(long timeout, TimeUnit unit) method. The thread calling this method keeps waiting until the execution of all tasks is complete or timeout period is elapsed or it is interrupted.

The isShutdown() method of ExecutorService returns true if it is shutdown. The isTerminated() method of ExecutorService returns true if all tasks are completed after shutdown.