Wednesday, 27 April 2016

Callable and Future in Java concurrency

Callable, an interface, was added in Java 5. It allows you to define a task to be completed by a thread asynchronously.

You must be wondering, there is already a Runnable interface, with its run() method to do the same thing then why Callable? Problem with Runnable is it can't return a value. It offers a single method run() that accepts no arguments and returns no values, nor can it throw any checked exceptions.

So if you have to use Runnable in scenario where you want to return some value, you'll have to write a method outside the interface to get a value back from the completed task, Also you need some kind of notification to know that the task is completed and now value can be retrieved.

Callable provides the functionality out of the box to implement the scenario as stated above.

Callable interface

The Callable interface has a call() method, since it is a generic interface so it can return any value (Object, String, Integer etc.) based on how it is initialized.

Note that Callable is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

General form of Callable interface

public interface Callable<V> {
    V call() throws Exception;
}

Runnning a task using Callable

Like Runnable you cannot pass a Callable into a thread to execute, you use the ExecutorService, which has a submit() method which takes Callable as parameter to execute the Callable task.

<T> Future<T> submit(Callable<T> task)

Here task is the Callable task to submit and it returns a Future representing pending completion of the task.

Future interface

A Future represents the result of an asynchronous computation. When you submit a callable task using the submit() method of the ExecutorService, Future object is returned.

Future provides methods to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation.

get() - get() method retrieves the result of the computation, blocking if necessary for the computation to complete.

If you don't want to get blocked indefinitely, you can use the version of the get() method with the timeout parameter, then it will wait only for the given time.
get(long timeout, TimeUnit unit) - Waits if necessary for at most the given time for the computation to complete, and then retrieves its result, if available.

You can also cancel the submitted task using cancel() method.

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

This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. Returns false if the task could not be cancelled, typically because it has already completed normally; true otherwise.

There is also isDone() method to check if task is completed and isCancelled() to check whether the task was cancelled before it was completed normally.

Example code using Callable and Future

In this example code there is a MyCallable class that implements the Callable interface and the return value of the call() method is String and its length.

A thread pool of four threads is created and submit() method of ExecutorService is used to submit callable tasks. Total submitted tasks are 6.
Also one tempMethod() is called just to show the asynchronous nature of the callable. While getting the future values isDone() method is used for the fourth get() to check whether that particular task is completed or not.

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableDemo {
    public static void main(String args[]){
        // ExecutorService with pool of 4 threads
        ExecutorService es = Executors.newFixedThreadPool(4);
        // Submitting 6 tasks
        Future<String> f1 = es.submit(new MyCallable("callable"));
        Future<String> f2 = es.submit(new MyCallable("future"));
        Future<String> f3 = es.submit(new MyCallable("executor"));
        Future<String> f4 = es.submit(new MyCallable("executor service"));
        Future<String> f5 = es.submit(new MyCallable("executors"));
        Future<String> f6 = es.submit(new MyCallable("scheduled executor"));
        // calling some other methods
        tempMethod();
        
        try {
            // Calling get() method to get the future value
            System.out.println("1. " + f1.get());
            System.out.println("2. " + f2.get());
            System.out.println("3. " + f3.get());
            if(f4.isDone()){
                System.out.println("4. " + f4.get());
            }else{
                System.out.println("waiting");
            }
            System.out.println("5. " + f5.get());
            System.out.println("6. " + f6.get());
        } catch (InterruptedException | ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //shutting down the executor service
        es.shutdown();
    }
    
    //
    public static void tempMethod(){
        System.out.println("I am in temp method");
    }
}

/**
 *
 * Callable
 *
 */
class MyCallable implements Callable<String> {
    String str;
    MyCallable(String str){
        this.str = str;
    }
    @Override
    public String call() throws Exception {
        System.out.println("In call method of Callable " + str);
        StringBuffer sb = new StringBuffer();
        return (sb.append("Length of string ").append(str).append(" is ").
                append(str.length())).toString();
    
    }
    
}

Output

In call method of Callable callable
In call method of Callable future
In call method of Callable executor
I am in temp method
1. Length of string callable is 8
2. Length of string future is 6
3. Length of string executor is 8
waiting
In call method of Callable executors
In call method of Callable scheduled executor
5. Length of string executors is 9
6. Length of string scheduled executor is 18
In call method of Callable executor service

It can be seen here that after 3 calls to callable tempMethod() is called in between while the Callable tasks are executed asynchronously. Also notice that fourth value is not there as a check for completion of task is there with isDone(), since the task is not completed and we are not blocking by calling the get() method so that particular value is skipped.
The output may differ when you execute the code.

Callable as lambda expression

As already stated above that Callable is a functional interface so it can be implemented as a lambda expression too. If we have to write the code as above using the lambda expression then it can be done this way -

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableLambda {
    public static void main(String args[]){
        ExecutorService es = Executors.newFixedThreadPool(4);
        getLength(es, "executor");
        getLength(es, "executor service");
        getLength(es, "Scheduled executor service");
        getLength(es, "executors");
        getLength(es, "fork join");
        getLength(es, "callable");
        
        
    }
    
    public static void getLength(ExecutorService es, String str){
        Future<String> f = es.submit(() -> { return str + str.length();});
        try {
            System.out.println("" + f.get());
        } catch (InterruptedException | ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Output

executor8
executor service16
Scheduled executor service26
executors9
fork join9
callable8

In the code Callable is implemented as a lambda expression with in the sumbit() method of the ExecutorService. Also, if you noticed the try-catch block in the code, multi catch statement from Java 7 is used here.

That's all for this topic Callable and Future in Java concurrency. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Executor and ExecutorService in Java concurrency
  2. LinkedBlockingDeque in Java
  3. Difference between Runnable and Callable in Java
  4. CopyOnWriteArrayList in Java
  5. ReentrantReadWriteLock in Java
  6. Java Concurrency interview questions

You may also like -

No comments:

Post a Comment