Multi-Threading in JAVA using Callables
Tags: java, concurrency, programming, softwaredevelopment
Published: 2023-09-14 14:19:45

## **Introduction to Callables**

In multi-threaded programming, we often encounter scenarios where tasks need to be executed concurrently, but they don't necessarily need to return any values. Think of these tasks as workers performing their jobs independently, like chefs work simultaneously to execute their tasks, and they don't need to return any specific information. In such cases, `runnables` can be used where there is nothing to return.


![Kitchen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zjjyinen3sy22pkqy2ie.jpeg)

However, there are situations where not only do we need tasks to run concurrently, but we also need them to return some valuable data upon completion. This is where the concept of `Callables` comes into play.

Let’s understand with an example:

#### Online Shopping:

Imagine you are an online shopper placing multiple orders. You want to track the status of each order and get confirmation when each order is successfully processed. This is where the concept of **`Callable`** comes in.


![Shopping](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qa6r29y2262myf9u3jsb.jpeg)

- **Callable** is like each online order you've placed. These are the tasks you care about because you want to track the status of your orders.
- **Future** is like the shipping confirmation email you receive for each order. When an order is shipped (the task is completed), you get an email (Future) that tells you the order's status and provides tracking information.

## Using Callables in Multi-Threaded Programs

To incorporate `Callables` into multi-threaded programs, you can follow these steps:

### Step 1: Identify Tasks Needing Data Returns

Identify `tasks` within your program that require data to be returned upon completion. These tasks are analogous to online shopping orders where you want tracking information.

### Step 2: Create Callable Classes

For tasks that need to return data, create classes and implement the **`Callable`** interface. This interface allows tasks to return results or throw exceptions, making it suitable for data-retrieval tasks.

```
import java.util.concurrent.Callable;

class OrderProcessingTask implements Callable<String> {
    private String item;

    public OrderProcessingTask(String item) {
        this.item = item;
    }
}
```
### Step 3: Implement the `call()` Method

Inside your `Callable` class, implement the **`call()`** method, which contains the code for the task and defines the return type for the method. This method represents the work that needs to be done and returns the result upon completion.

```
@Override
public String call() throws Exception {
    // Simulate order processing
    Thread.sleep(2000); // Simulating processing time
    return "Order for " + item + " is processed.";
}
```
### Step 4: Create a Main Class Using Executor Service

Create a main class that utilizes the **`ExecutorService`** to execute the Callable tasks:

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

public class OnlineShoppingApp {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // Create order processing tasks
        Callable<String> order1 = new OrderProcessingTask("Product A");
        Callable<String> order2 = new OrderProcessingTask("Product B");
        Callable<String> order3 = new OrderProcessingTask("Product C");

        // Submit tasks to the executor
        Future<String> result1 = executor.submit(order1);
        Future<String> result2 = executor.submit(order2);
        Future<String> result3 = executor.submit(order3);

        // Wait for tasks to complete and retrieve results
        String status1 = result1.get();
        String status2 = result2.get();
        String status3 = result3.get();

        System.out.println(status1);
        System.out.println(status2);
        System.out.println(status3);

        // Shutdown the executor when done
        executor.shutdown();
    }
}
```

### Understanding the use of `Future` with `Callable`

In the main class, we use **`Future`** objects to capture the results of the submitted **`Callable`** tasks. A **`Future`** represents the result of an asynchronous computation, in this case, the result of each order processing task.

> 
### Analogy:
In our example scenario of Online Shopping, each order represents a separate task, and we want to keep track of their status and delivery. So:
- `Callable` is analogous to an online shopping order. Each order represents a task that we want to track.
- `Future` is like the order confirmation or tracking number we receive after placing an online order. It’s a reference to our order’s status and allows us to retrieve details when the order is processed.

Just like you can check the status of our online orders using the order number without waiting at the store, we can use `Future<>` to check the status and retrieve results from Callable tasks without blocking the program.
>

Here's how this works:
- **`executor.submit(callable)`** returns a **`Future`** representing the result of the callable task.
- **`result.get()`** is called to retrieve the result of the task.

This allows to efficiently manage tasks that return data in a multi-threaded program. The **`Future`** provides a way to obtain the result of the task when it's ready, just like tracking online orders and receiving status updates when the orders are processed.

### Closing Thoughts:
Thank you for reading our blog. We appreciate your time and interest in our content. If you have any questions, feedback, or topics you’d like us to cover in our future articles, please feel free to leave a comment below. Your input is valuable, and it helps us create content that matters to you.

Stay connected with us for more insightful articles on various topics related to technology, programming, and much more.

Happy coding!