Monday, November 20, 2006

Java 5 Concurrency: Callable and Future

Till Java 1.4, threads could be implemented by either implementing Runnable or extending Thread. This was quite simple, but had a serious limitation - They have a run method that cannot return values. In order to side-step this, most programmers use side-effects (writing to a file etc.) to mimic returning values to the invoker of the thread. Java 5 introduces the Callable interface, that allows users to return values from a thread. This post describes the Callable and Future interfaces and shows an example of how to use these to interfaces.
Jump to Sample Code
public interface Callable<V> {
V call() throws Exception;
}
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.
A Future represents the result of an asynchronous computation.
public interface Future {

//Attempts to cancel execution of this task.
boolean cancel(boolean mayInterruptIfRunning);

boolean isCancelled();

boolean isDone();

// Waits if necessary for the computation to complete,
// and then retrieves its result.
V get() throws InterruptedException, ExecutionException;

// Waits if necessary for at most the given time for the computation
// to complete, and then retrieves its result, if available.
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
The result can be retrieved using method get() when the computation has completed, blocking if necessary until it is ready. If you would like to use a Future for the sake of cancellation but not provide a usable result, you can declare types of the form Future<?> and return null as a result of the underlying task. The following example demonstrates the use of Callable and future. The first CallableImpl class implements the Callable interface, and returns an integer that is sent to it's constructor. The CallableTester class invokes the CallableImpl through an executor.
public class CallableImpl implements Callable<Integer> {

private int myName;
CallableImpl(int i){
myName = i;
}

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

}

public int getMyName() {
return myName;
}

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

}
CallableImpl.java
public class CallableTester {

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();
}
}

}
CallableTester.java

ExecutorService extends Executor to provides method to manage thread termination and methods that can produce a Future for tracking progress of one or more asynchronous tasks. The method submit extends Executor.execute(java.lang.Runnable) to create and return a Future. Methods invokeAny and invokeAll perform the most commonly useful forms of bulk execution, executing a collection of tasks and then waiting for at least one, or all, to complete. For an overview of Executors, visit Java 5 Executors.

2 comments:

  1. Thank you for this useful blog post. One thing: you wrote "To implement Callable with no return value, use Callable<void>". I think you probably wanted to write

    Callable<Void>

    instead. That's Void with a capital letter V.

    ReplyDelete
  2. Hi Abhi,

    I love you blog. I have a question about shutting down redundant threads. Based on your blogs i have a main class that creates new threads like so..
    ..
    ...
    ExecutorService executorService = Executors.newCachedThreadPool();
    ...
    ...
    void startNewThread(){
    if(condition){

    //create a new thread
    Callable callableHorseRaceThread = new HorseRaceThreadCallable(currentMarketID, currentExchangeID, sessionToken);

    //start the thread
    executorService.submit(callableHorseRaceThread);

    }
    }

    This starNewThread() method is periodiocally called on a Timer. If the condition has changed..e.g a new race is available, it start a new thread. The thread that has been created is itself repetitively calling methods on a timer. e.g reading info from the internet.

    How do I gracefully shutdown the created threads(Callable callableHorseRaceThread) when certains conditions have changed?

    Thanks for your help and keep up the blog.

    Brian

    ReplyDelete

Popular Posts