avatarUğur Taş

Summary

In Java, Runnable and Callable are two distinct interfaces used for concurrent task execution, with Runnable lacking a return value and exception handling capabilities, while Callable can return a result and handle exceptions, providing more robust options for multithreaded applications.

Abstract

Java provides two primary interfaces, Runnable and Callable, for defining and executing concurrent tasks. Runnable, part of the java.lang package, is a straightforward interface with a single run() method that does not return a value and cannot throw checked exceptions. It is suitable for tasks that do not require a result or exception handling. In contrast, Callable, introduced in Java 5 and part of the java.util.concurrent package, defines a call() method that can return a result and throw exceptions, allowing for more sophisticated error handling and the retrieval of task outcomes. Callable tasks are typically executed using an ExecutorService, which returns a Future object that represents the pending result of the computation. This enables the retrieval of the result and the handling of exceptions after the task has been completed. The choice between Runnable and Callable depends on the specific needs of the application, with Runnable being appropriate for simple, fire-and-forget tasks, and Callable being the preferred choice for tasks that require result retrieval and comprehensive exception handling.

Opinions

  • The author suggests that understanding the differences between Runnable and Callable is crucial for efficient multithreaded application development in Java.
  • The use of ExecutorService for executing both Runnable and Callable tasks is recommended for better control and management of thread pools.
  • Callable is seen as a more advanced and robust alternative to Runnable due to its ability to return results and handle exceptions, making it suitable for complex concurrent tasks.
  • The article implies that the choice between Runnable and Callable should be made based on the task requirements, with Callable offering additional features that are beneficial for tasks needing result retrieval and exception handling.
  • The author encourages readers to engage with the content by clapping, sharing, and providing feedback, indicating a desire for community interaction and content improvement.
  • The author promotes their social media profiles and other articles, suggesting a commitment

Runnable vs Callable in Java

In Java, there are two main interfaces that are used to define tasks that can be executed concurrently — Runnable and Callable. Both of these interfaces serve as essential tools for managing threads in Java, but they have distinct characteristics and use cases. Understanding the differences between these two interfaces is important for writing efficient multithreaded applications in Java.

Runnable

The Runnable interface is part of the java.lang package and represents a task that can be executed concurrently by a thread. It defines a single abstract method, run(), which contains the code that will be executed when the thread is started.

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

Runnable is a simple and straightforward way to create and start a new thread in Java. It doesn't return any result after execution, making it suitable for tasks that are meant to run independently. To create a runnable task, you simply need to implement the run() method. For example:

public class MyRunnable implements Runnable {

  @Override
  public void run() {
    // task code here 
  }

}

You can then pass an instance of MyRunnable to a Thread constructor to execute it asynchronously.

Callable

On the other hand, the Callable interface, introduced in Java 5, is part of the java.util.concurrent package. It is a more advanced alternative to Runnable. Unlike Runnable, Callable's main method, call(), can return a result or throw an exception.

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

This feature allows for more complex and robust thread management, as you can obtain the results of the execution and handle exceptions gracefully. Callable is often used when you need to perform tasks concurrently and collect their results or if you need more control over the execution. Callable also works with Java’s ExecutorService to submit tasks and receive Future objects representing the pending result of computation. For example:

class MyCallable implements Callable<Integer> {

  @Override
  public Integer call() throws Exception {
    // task code 
    return result; 
  }

}

// submit Callable to ExecutorService
Future<Integer> future = executorService.submit(new MyCallable()); 

// retrieve result later
int result = future.get();

Callable can only be executed by ExecutorService. But Runnable can be executed by Runnable and the ExecutorService. Because Thread is an implementation of a Runnable.

Differences of Runnable and Callable

Return Value

The most significant difference between Runnable and Callable is the return value. Runnable’s run() method doesn't return anything, whereas Callable's call() method can return a value (or throw an exception).

Exception Handling

With Runnable, you have limited control over exceptions. Runnable’s run() method definition does not throw any exceptions, so any Checked Exceptions need to be handled in the run() implementation method itself. Any unhandled exception will propagate to the thread’s uncaught exception handler. In contrast, Callable allows you to capture exceptions and handle them appropriately within your code.

Usage with Executors

Both Runnable and Callable can be submitted to executor services (e.g., ExecutorService or ThreadPoolExecutor). Runnable tasks can be submitted using the execute() method, whereas Callable tasks are submitted with the submit() method. The latter returns a Future object that can be used to retrieve the result.

Runnable Example

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

public class RunnableExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        Runnable task = () -> {
            System.out.println("This is a Runnable task.");
        };

        executor.execute(task);

        executor.shutdown();
    }
}

In this Runnable example, we create a simple task and execute it using an ExecutorService.

// Runnable that cannot return result
class GetDataRunnable implements Runnable {

  @Override 
  public void run() {
    // call API
    String result = httpClient.sendRequest();
    
    // process result
    processString(result); 
  }

}

public class RunnableExample {
  public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        executor.execute(new GetDataRunnable());

        executor.shutdown();
    }
}

In the above example, code shows how we might use Runnable to fetch data from a remote API and process the result.

Callable Example

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

public class CallableExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        Callable<String> task = () -> {
            Thread.sleep(2000);
            return "This is a Callable task.";
        };

        Future<String> result = executor.submit(task);

        try {
            String message = result.get();
            System.out.println(message);
        } catch (Exception e) {
            e.printStackTrace();
        }

        executor.shutdown();
    }
}

In the Callable example, we execute a task that returns a result, which we retrieve using the Future object. We also demonstrate exception handling.

// Callable that returns result
class GetDataCallable implements Callable<String> {

  @Override
  public String call() throws Exception {
    // call API 
    return httpClient.sendRequest();
  }

}

public class RunnableExample {
  public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();

        // submit and receive future
        Future<String> future = executorService.submit(new GetDataCallable());
        
        // process future later 
        String result = future.get(); 
        processString(result);

        executor.shutdown();
    }
}

In the above example, the code shows how we might use Callable to fetch data from a remote API and process the result.

In summary, Runnable is useful for fire-and-forget tasks that do not need to return results. On the other hand, Callable provides more control, allowing you to handle exceptions and obtain the result of the task, because it works with Futures. Understanding these differences allows you to pick the best interface to suit the concurrent needs of your application.

👏 Thank You for Reading!

👨‍💼 I appreciate your time and hope you found this story insightful. If you enjoyed it, don’t forget to show your appreciation by clapping 👏 for the hard work!

📰 Keep the Knowledge Flowing by Sharing the Article!

✍ Feel free to share your feedback or opinions about the story. Your input helps me improve and create more valuable content for you.

✌ Stay Connected! 🚀 For more engaging articles, make sure to follow me on social media:

🔍 Explore More! 📖 Dive into a treasure trove of knowledge at Codimis. There’s always more to learn, and we’re here to help you on your journey of discovery.

Runnable
Callable
Java
Multithreading
Callable Function
Recommended from ReadMedium