In this article we will discuss how to use the new interface Callable introduced in java.concurrent.util in Java 5. Callable along with another interface Future allows us to obtain a return value from a method executed in a separate thread.
In the second example we will also examine the usage of FutureTask, an implementation of Future.
The run() method in classic Runnable interface or Thread class in Java does not have a return value. So if we had to return a value from a method execution we had to create an instance variable and return it using a getter method. While we do so, we have to remember to make a defensive copy.
But no more of this workaround. In Java 5, we have two interfaces Callable and Future which can be combined to obtain a return value from a method executed in a separate thread.
In following code snippet (Code Snippet 1) we have a simple class CallableBake that implements the Callable interface.
Code Snippet 1
- class CallableBake implements Callable {
- ArrayList<Integer> cakes=new ArrayList<Integer>(100);
- public ArrayList<Integer> call() throws Exception {
- for (int i=0; i<10;i++){
- cakes.add(i);
- //throw new RuntimeException("Hello");
- //this will cause Execution exception when you get Future.get()
- }
- return cakes;
- }
- }
The method call() is the equivalent of our good old run() method. As we might have noticed, it can also throw an Exception, another thing run() couldn't do.
Now to executed the call() method in a separate thread, let's use one of the Executor implementations.
Code Snippet 2:
- ThreadPoolExecutor executor =new ThreadPoolExecutor(2,10,100,TimeUnit.MILLISECONDS,blockingQueue);
- CallableBake callableBake=new CallableBake();
- Future future= executor.submit(callableBake);
- //future.cancel(false);
We create an instance of CallableBake class and pass it as an argument to submit(). Please note, we cannot directly pass CallableBake to the execute() method, submit() will place it as a task in the queue and get executed.
Code Snippet 3
- try {
- ArrayList<Integer> cakeList = (ArrayList<Integer>) future.get();
- System.out.println("Is the task done: "+ future.isDone());
- System.out.println("Return value from Callable ->No. of cakes:" + cakeList);
- } catch (CancellationException ce)
- {
- System.out.println("Is the task cancelled: "+ future.isCancelled());
- ce.printStackTrace();
- } catch (InterruptedException e)
- {
- // if the thread was interrupted.
- e.printStackTrace();
- } catch (ExecutionException e)
- {
- // if the call method threw an exception.
- System.err.println(e.getMessage());
- e.printStackTrace();
- }
In line 9 of snippet 1, we can see that call() method returns an ArrayList of String objects, and in line 2 of code snippet 3, we call a Future.get() to obtain that ArrayList object. What you will see printed on the console is
- Is the task done: true
- Return value from Callable ->No. of cakes:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
If we cancel the task using the commented code in line 4 of code snippet 2, we cannot obtain the return value using Future.get(). This method will throw a CancellationException.
If the call() method throws any exception it can be caught in the catch block after Future.get() as shown in code snippet 3. These exceptions are always thrown when we call the Future.get() not when Executor.submit() method is called.
Another way of getting the same effect would be to use the class FutureTask which inherits from both Runnable and Future interfaces.
Code snippet 4
- CallableBake callableBake=new CallableBake();
- FutureTask futureTaskWrapper = new FutureTask(callableBake);
- executor.execute(futureTaskWrapper);
- //remember FutureTask implements Future and Runnable.
- try {
- System.out.println(futureTaskWrapper.get());
- } catch (InterruptedException e) {
Here we wrap the callable instance with FutureTask object and pass the FutureTask instance to execute method of the Executor. In line 6 in code snippet 4, we can obtain the return value of the call() method.
So to summarize, if we want to get return values from a method() from a separate thread, use Callable instead of Runnable along with Future or FutureTask. If we are writing a new multi-threaded code, there is no need to use Runnable. Callable is the new Runnable.
P.S.
Entire code sample is attached, it has been compiled and run under JVM 1.5.0_09
In the next article, we will talk about using various implementations of Atomic variables.













Hi!
Thanks for this illuminating tutorial on how to use futures in Java. One thing bothered me, though: The use of raw types instead of generic ones. I think using
and especially
would have made made sure that programmers who are just learning to use Java start on the right track, with as much type safety as Java can give them.
Perhaps you can still rewrite the article. In that case, it might make sense to create a Cake class; with a list of Integers, a reader may be wondering why that was chosen.
Thanks again. I'm sure I'll use your article as reference.
--Mathias Ricken
Hi Mathias,
Valuable feedback. I will make the suggested changes and repost soon..
Thanks,
Sharad
Mathias,
I have modified the example to use Generic Types...
It worth noting that if you shutdown an ExecutorService, the Future objects it created are left hanging. i.e. they will never be done and your waiting thread has no idea they will not be done.
One way around this is to use reflection to get the underlying ExecutorService and periodically checking that it has not shutdown. Unfortunately Java does not do this for you.
This can be a problem in unit tests where you need a graceful shutdown of your components.
Good Point!
ThreadPoolExecutor.shutdown() causes all the threadpool to shutdown and any unexecuted tasks will not be executed. But shutdown() is not a blocking call. After shutdown() returns the threads (tasks) can still be running. The best way to examine Future objects would be after a call awaitTermination() which is a blocking call. I will modify my example to reflect this.
This is not really need as Future.get() is a blocking call, it waits for the task to complete.
You probably meant shutdownNow(), which will cause the threads to be terminated.
For detailed examples on using Executor, please see an earlier articles on Executor at
http://www.techgrasp.com/blogs/sharadjava/java-concurrency-series-simple...
http://www.techgrasp.com/blogs/sharadjava/java-concurrency-series-anothe...
Thanks,
Sharad
Post new comment