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:
Callable
interfaceCallable
taskExecutorService
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:
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.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.