October 19, 2022

Java Callable And Future With Examples

In this post we’ll see two of the interesting features of the concurrent API, Callable and Future in Java.

Callable in Java

Consider a scenario where you have a big computation and you want to split it into multiple sub-tasks which are executed by multiple threads with each thread working on a part of the task. Once all the threads are finished with their tasks you can combine the partial results to get the result of the computation.

Designing this scenario with Runnable makes it difficult as Runnable doesn’t return a result. That shortcoming is filled by Callable in Java as it can return a result and may throw an exception.

Callable interface

Callable interface in Java has a single method call() which computes a result and returns it or throws an exception if unable to do so.

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

So, you need to implement call() method to provide the task that has to be implemented by a thread as an asynchronous computation. Here is a simple example of Callable implementation-

Callable<String> callable = new Callable<String>() {
  public String call() {
    return "Value returned from Callable";
  }
};

Since Callable is a functional interface it can also be implemented as a lambda expression.

Callable<String> callable = ()->{
  return "Value returned from Callable";
};

Running a Callable task using ExecutorService

To execute a Callable, submit() method of ExecutorService is used.

<T> Future<T> submit(Callable<T> task)- Submits a callable task which returns value for execution and returns a Future representing the pending results of the task.

When a callable task is submitted it is executed in its own thread asynchronously. It is not known when the result of that asynchronous computation will be available, all we know is it will be available in some future. Thus an appropriately named interface Future represents the return value of the callable task.

Java Callable and Future example

Here is a simple example showing how callable task is submitted using ExecutorService and how to obtain the returned value using Future.

public class CallableDemo {
  public static void main(String[] args) {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Date date = new Date();
    System.out.println("Submitting callable task " + date);
    // submitting callable task
    Future<String> future = executor.submit(()->{
      TimeUnit.SECONDS.sleep(4);
      return "Value returned from Callable";
    });
    System.out.println("Submitted callable task " + new Date());
    // getting result 
    try {
      System.out.println("Returned value-" + future.get() + " at " + new Date());
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    executor.shutdown();
  }
}
Output
Submitting callable task Tue Dec 04 11:18:05 IST 2018
Submitted callable task Tue Dec 04 11:18:05 IST 2018
Returned value-Value returned from Callable at Tue Dec 04 11:18:09 IST 2018

As you can see the callable task is submitted for execution to execute in its own thread and the main thread resumes its execution (second System.out is executed immediately after callable submission).

Then the get method is called to retrieve the result of the computation, since get() is a blocking call so it waits for the computation to complete if required.

Future in Java

Future represents the result of an asynchronous computation.

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

  • cancel(bollean interruptFlag)- Attempts to cancel execution of this task.
  • get()- Waits if necessary for the computation to complete, and then retrieves its result.
  • 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.
  • isCancelled()- Returns true if this task was cancelled before it completed normally.
  • isDone()- Returns true if this task completed.

Callable and Future example

Here is an example of callable and future where 4 callable tasks are executed using the pool of two threads.

public class CallableDemo {
  public static void main(String[] args) {
    // Pool of 2 threads
    ExecutorService executor = Executors.newFixedThreadPool(2);
    System.out.println("Submitting callable tasks " + new Date());
    Future<String> f1 = executor.submit(new MyCallable("Callable task-1"));
    Future<String> f2 = executor.submit(new MyCallable("Callable task-2"));
    Future<String> f3 = executor.submit(new MyCallable("Callable task-3"));
    Future<String> f4 = executor.submit(new MyCallable("Callable task-4"));
    System.out.println("Submitted callable task " + new Date());
                
    // getting result 
    try {
      // Calling get() method to get the future value
      System.out.println("Value for task-1 " + f1.get() + " at " + new Date());
      System.out.println("Value for task-2 " + f2.get() + " at " + new Date());
      while(!f3.isDone()) {
        System.out.println("Waiting for task-3 to complete " + f2.get());
        TimeUnit.MILLISECONDS.sleep(500);
      }
      System.out.println("Value for task-3 after it is completed " + f3.get() + " at " + new Date());
      System.out.println("Value for task-4 " + f4.get() + " at " + new Date());
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
      executor.shutdown();
  }
}

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, thread name- " + Thread.currentThread().getName());
    TimeUnit.SECONDS.sleep(2);
    return str;
  }
}
Output
Submitting callable tasks Tue Dec 04 11:47:23 IST 2018
Submitted callable task Tue Dec 04 11:47:23 IST 2018
In call method, thread name- pool-1-thread-1
In call method, thread name- pool-1-thread-2
In call method, thread name- pool-1-thread-2
In call method, thread name- pool-1-thread-1
Value for task-1 Callable task-1 at Tue Dec 04 11:47:25 IST 2018
Value for task-2 Callable task-2 at Tue Dec 04 11:47:25 IST 2018
Waiting for task-3 to complete Callable task-2
Waiting for task-3 to complete Callable task-2
Waiting for task-3 to complete Callable task-2
Waiting for task-3 to complete Callable task-2
Value for task-3 after it is completed Callable task-3 at Tue Dec 04 11:47:27 IST 2018
Value for task-4 Callable task-4 at Tue Dec 04 11:47:27 IST 2018

As you can see from the output two callable tasks are executed by one thread and two tasks are executed by another thread from the thread pool. In the example isDone() method is also used to check if the submitted task is completed or not.

That's all for the topic Java Callable And Future With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment