Tuesday, June 14, 2011

The Callable Interface

One of the beautiful things about Java from its very first release was the ease with which we could write multi-threaded programs and introduce asynchronous processing into our designs. The Thread class and Runnable interface combined with Java’s memory management model meant for straightforward thread programming.

The run() method in Runnable cannot return a result (i.e. it returns void) and cannot throw a checked exception. If you try to throw an exception in a run() method, the javac compiler insists that you use a throws clause in the method signature. However, the superclass run() method doesn't throw an exception, so javac will not accept this. The lack of thrown checked exceptions was a little more serious.

Even if you were careful and you stored these for later verification, you couldn’t force all uses of the class to check the exception. You could go through all your getters and throw the Exception if it existed on each one. Besides being cumbersome, even that wasn’t foolproof. You couldn’t enforce calls to any of these. Thread programmers would correctly call join() to wait for it complete and may then have gone on their merry way.

The new java.util.concurrent.Callable interface is much like Runnable but overcomes two drawbacks with Runnable.
The interface looks like this :
public interface Callable<V> {
V call() throws Exception;
}


Implementing Runnable to get returned value
If you need a result from a Runnable task, you have to provide some external means of getting that result. A common technique is to set an instance variable in the Runnable object and provide a method to retrieve that value. For example,

public MyRunnable implements Runnable
{
private int fResult = 0;
public void run () {
...
fResult = 1;
} // run

// A getter method to provide the result of the thread.
public int getResult () { return fResult; }

} // class MyRunnable


Even if you were careful and you stored these for later verification, you couldn’t force all uses of the class to check the exception. You could go through all your getters and throw the Exception if it existed on each one. Besides being cumbersome, even that wasn’t foolproof. You couldn’t enforce calls to any of these. Thread programmers would correctly call join() to wait for it complete and may then have gone on their merry way.
Implementing the Callable
The Callable interface solves these problems. Instead of a run() method the Callable interface defines a single call() method that takes no parameters but is allowed to throw an exception. A simple example is

import java.util.concurrent.*;
public class MyCallable implements Callable
{
public Integer call () throws java.io.IOException {
return 1;
}
} // MyCallable

This call() method returns an Integer. (Note that we have conveniently used the autoboxing support in J2SE 5.0 to have the literal int 1 value automatically boxed into an Integer return value.)

Note
The call() method is the entry point into a Callable object, and it's return type is the type parameter set in the Callable object. To implement Callable with no return value, use Callable<void>. Also, note that the call() method throws a checked exception, as compared to the run() method in Runnable which does not throw any exception. The Executors class contains utility methods to convert from other common forms to Callable classes. However, Callable cannot be used in place of a Runnable. Callable objects have to be invoked by ExecutorService. The Executor framework provides the Future interface to allow handling the cancellation and returns of a Callable object.

Getting the return value from a Callable depends upon the new generics feature:

FutureTask task = new FutureTask (new MyCallable ());
ExecutorService es = Executors.newSingleThreadExecutor ();
es.submit (task);
try {
int result = task.get ();
System.out.println ("Result from task.get () = " + result);
}
catch (Exception e) {
System.err.println (e);
}
es.shutdown ();

Here, we use the FutureTask class that supports an Integer return value. Then the task is submitted using the ExecutorService submit() method, and the result is obtained from the FutureTask get() method, again using auto-unboxing to convert the Integer to an int. See the API documentation for more information on ExecutorService, and FutureTask.

 

Callable Example


CallableImpl.java


package com.vaani.callable;

import java.util.concurrent.Callable;

public class CallableImpl implements Callable<Integer> {

private int name;
public CallableImpl(int i){
name = i;
}

public Integer call() {
for(int i = 0; i < 10; i++) {
System.out.println("Thread : " + getName() + " I is : " + i);
}
return new Integer(getName());

}

public int getName() {
return name;
}

public void setMyName(int myName) {
this.name = myName;
}

}

CallableDemo.java



public class CallableDemo {

public static void main(String[] args) {
Callable<Integer> callable = new CallableImpl(2);

ExecutorService executor = new ScheduledThreadPoolExecutor(5);
Future<Integer> future = executor.submit(callable);

try {
System.out.println("Future value: " + future.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}

Also we have future which is similar to Callable except Future represents the result of an asynchronous computation. But it is discussed here.







Download the source


Source code can be downloaded from here.

No comments:

Post a Comment

Chitika