Java
Runnable Interface
Callable Interface
Programming
Multithreading

The difference between the Runnable and Callable interfaces in Java

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

In Java, concurrency is a powerful feature that allows the execution of multiple threads simultaneously, enhancing performance especially in application environments where multiple tasks need to be executed concurrently or where operations are blocking in nature. To facilitate concurrency, Java provides several mechanisms, one of which involves using interfaces to encapsulate tasks that are executed by threads. The two primary interfaces provided by Java for such purposes are Runnable and Callable.

Understanding Runnable

Runnable is one of the oldest interfaces in Java, introduced in Java 1.0. It is found in the java.lang package. The Runnable interface is designed to encapsulate a unit of executable code which can be executed by a thread. It has a single method called run() that does not accept any arguments and does not return any value (void return type):

java
1@FunctionalInterface
2public interface Runnable {
3    void run();
4}

Understanding Callable

Callable, introduced later in Java 1.5, is a more versatile and advanced counterpart to Runnable. It belongs to the java.util.concurrent package, which contains many of the enhancements for concurrency introduced in Java 1.5. Unlike Runnable, the Callable interface is generic and its single method call() returns a value and is able to throw an exception:

java
1@FunctionalInterface
2public interface Callable<V> {
3    V call() throws Exception;
4}

The return type V represents the type of value that the Callable task returns after its execution.

Key Differences

  1. Return Value:
    • Runnable: The run() method does not return any value.
    • Callable: The call() method returns a value, the type of which can be defined as per the requirements.
  2. Exception Handling:
    • Runnable: The run() method cannot throw any checked exceptions; it can only handle exceptions internally or throw unchecked exceptions.
    • Callable: The call() method can throw checked exceptions, allowing the callers to handle them.
  3. Usage with Executor Services:
    • Runnable: When submitted to an executor service, no value can be obtained directly from the Runnable after its execution.
    • Callable: When a Callable is submitted to an executor service, it returns a Future object, which can be used to retrieve the result of the Callable’s call() method asynchronously.

Here is a summary table of their differences:

FeatureRunnableCallable
Return typevoidGeneric type V
ExceptionNo checked exceptions allowedCan throw checked exceptions
Result retrievalNone directly from RunnableVia Future from executor service

Practical Scenarios

  • Runnable: Ideal for simple concurrency tasks, especially for fire-and-forget operations where no result is needed post execution, such as periodic cleanup tasks or triggers in a web server.
  • Callable: Suitable for tasks requiring computation that needs to return a result or status, such as processing a large data set and returning a computed result, or where operations may throw exceptions that need to be managed, such as when interacting with I/O operations.

Examples

Runnable Example:

java
1Runnable runnableTask = () -> {
2    System.out.println("Executing runnable task");
3};
4new Thread(runnableTask).start();

Callable Example:

java
1Callable<String> callableTask = () -> {
2    return "Result from callable";
3};
4ExecutorService executorService = Executors.newFixedThreadPool(1);
5Future<String> future = executorService.submit(callableTask);
6try {
7    String result = future.get();  // Retrieves the result of the callable task
8    System.out.println(result);
9} finally {
10    executorService.shutdown();
11}

Conclusion

Choosing between Runnable and Callable typically depends on the requirements of the concurrency tasks within a Java application. If you need straightforward execution and do not require any results back from the thread, Runnable is adequate. However, for more complex needs where results, generic types, and exception handling are involved, Callable is the optimal choice. With the introduction of lambdas and enhanced concurrency utilities in recent versions of Java, implementing these interfaces has become more straightforward and powerful.


Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.