Friday, February 3, 2023

Callable interface in the Java Concurrent API

 

A Callable is an interface in the Java Concurrent API that represents a task that can return a result. A Callable task is similar to a Runnable task, but it can return a result. The result of a Callable task can be obtained by calling the get method on the Future returned by the ExecutorService.

Here is an example that demonstrates how to use a Callable task:


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 CallableExample { public static void main(String[] args) throws InterruptedException, ExecutionException { // Create a single-threaded executor ExecutorService executorService = Executors.newSingleThreadExecutor(); // Submit a Callable task to the executor service Future<String> future = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "Hello World"; } }); // Wait for the task to complete and get the result String result = future.get(); System.out.println(result); // Shut down the executor service executorService.shutdown(); } }

In this example, we create a single-threaded executor using the newSingleThreadExecutor method of the Executors class. We then submit a Callable task to the executor service using the submit method. The task returns the string "Hello World".

We wait for the task to complete using the get method on the Future returned by the submit method. Finally, we shut down the executor service using the shutdown method.

The output of this program is:

Hello World

As with the Runnable task, the order in which the Callable task is executed is not guaranteed. The Callable task is executed by a single thread in the executor service, and the order in which it completes is not specified.

A Callable task can also throw an exception, just like a Runnable task. In that case, the exception is propagated to the calling thread when the get method is called on the Future. Here is an example:

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 CallableExceptionExample { public static void main(String[] args) { // Create a single-threaded executor ExecutorService executorService = Executors.newSingleThreadExecutor(); // Submit a Callable task to the executor service Future<String> future = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { throw new Exception("Task failed"); } }); try { // Wait for the task to complete and get the result String result = future.get(); System.out.println(result); } catch (InterruptedException e) { System.out.println("InterruptedException: " + e.getMessage()); } catch (ExecutionException e) { System.out.println("ExecutionException: " + e.getMessage()); } // Shut down the executor service executorService.shutdown(); } }

In this example, the Callable task throws an exception with the message "Task failed". When the get method is called on the Future, the exception is propagated to the calling thread and can be caught using a try-catch block.

The output of this program is:


ExecutionException: java.lang.Exception: Task failed

It's important to note that the ExecutorService does not automatically propagate exceptions from a Callable task to the calling thread. Instead, exceptions are propagated when the get method is called on the Future. This allows the calling thread to handle the exception appropriately, for example, by logging the error or retrying the task.


No comments:

Post a Comment