Runnable vs Callable in Java

1. Introduction

In Java, Runnable and Callable are two interfaces used for threading and task execution. Runnable has been part of Java since version 1.0 and represents a task that can be run by a thread. Callable was introduced in Java 5 and is similar to Runnable, but it can return a result and throw a checked exception.

2. Key Points

1. Runnable tasks do not return a result.

2. Callable tasks can return a result and throw checked exceptions.

3. Runnable has a run() method that does not return a value nor throw exceptions.

4. Callable has a call() method that returns a value and can throw an exception.

5. Runnable is typically used with threads, while Callable is used with ExecutorService, which can return Future objects.

3. Differences

Runnable Callable
Introduced in Java 1.0. Introduced in Java 1.5 as part of the concurrency package (java.util.concurrent).
Represents a command that can be executed by a thread. Represents a task that returns a result and may throw an exception.
The run() method does not return a value. The call() method returns a value and can throw an exception.
The run() method cannot throw checked exceptions, only unchecked exceptions. The call() method can throw checked exceptions.
Used with classes like Thread and interfaces like Executor. Used with concurrency utilities like FutureTask and ExecutorService.
Ideal for fire-and-forget tasks that do not need to return a result or throw checked exceptions. Suitable for tasks that need to return a result and might throw checked exceptions.

4. Example

import java.util.concurrent.*;

public class RunnableVsCallable {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // Using Runnable
        Runnable runnableTask = () -> {
            // Task implementation here
            System.out.println("Running runnable task");
        };
        Thread runnableThread = new Thread(runnableTask);
        runnableThread.start();

        // Using Callable
        Callable<String> callableTask = () -> {
            // Task implementation here
            return "Result from callable";
        };
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        Future<String> future = executorService.submit(callableTask);

        // Print result of callable
        System.out.println(future.get());

        // Shutdown the executor service
        executorService.shutdown();
    }
}

Output:

Running runnable task
Result from callable

Explanation:

1. The runnableTask implements Runnable and prints a message; it cannot return a result.

2. The callableTask implements Callable and returns a string; it can also throw exceptions.

3. future.get() is used to retrieve the result from the callableTask.

4. The executor service needs to be shut down explicitly after its use.

5. When to use?

Use Runnable when you want to run code in a thread without returning a result or throwing a checked exception.

- Use Callable when you need to return a result from your task or when your task might throw a checked exception and you want to handle it.

Comments