Java Interview Questions

30 Questions
Java

Java

Web DevelopmentBackend

Question 21

What is the difference between the 'Runnable' and 'Callable' interfaces?

Answer:

In Java, both Runnable and Callable are interfaces designed for representing tasks that can be executed by a thread or an executor service. However, they have some key differences, mainly in their method signatures and the way they handle results and exceptions. Here’s a detailed comparison:

Runnable Interface

Definition: The Runnable interface is a functional interface that is designed to represent a task that can be executed by a thread.

Method:

  • void run(): The run method does not return any value and does not throw any checked exceptions.

Example:

public class RunnableExample implements Runnable {
    @Override
    public void run() {
        System.out.println("Task is running.");
    }

    public static void main(String[] args) {
        RunnableExample task = new RunnableExample();
        Thread thread = new Thread(task);
        thread.start();
    }
}

Callable Interface

Definition: The Callable interface is a generic interface that is part of the java.util.concurrent package. It is designed to represent a task that can be executed by a thread and can return a result and throw a checked exception.

Method:

  • V call() throws Exception: The call method returns a result of type V and can throw a checked exception.

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 CallableExample implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        return 123;
    }

    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        CallableExample task = new CallableExample();
        Future<Integer> future = executor.submit(task);

        try {
            Integer result = future.get();
            System.out.println("Result: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }
}

Key Differences

  1. Return Type:

    • Runnable: The run method does not return a result.
    • Callable: The call method returns a result of type V.
  2. Exception Handling:

    • Runnable: The run method cannot throw checked exceptions.
    • Callable: The call method can throw checked exceptions.
  3. Usage Context:

    • Runnable: Typically used when you do not need a result from the task and do not need to handle checked exceptions. Often used with Thread class directly.
    • Callable: Used when you need a result from the task or need to handle checked exceptions. Often used with executor services and futures.
  4. Integration with Executors:

    • Runnable: Can be submitted to an ExecutorService using submit(Runnable task), but will return a Future<?> with a null result.
    • Callable: Can be submitted to an ExecutorService using submit(Callable<V> task), and will return a Future<V> with the result of the computation.

When to Use Each

  • Runnable: Use when the task does not need to return any result or throw any checked exceptions. Suitable for simple tasks that can be executed in a new thread or submitted to an executor.

    Example:

    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.submit(new Runnable() {
        @Override
        public void run() {
            System.out.println("Runnable task executed.");
        }
    });
    executor.shutdown();
  • Callable: Use when the task needs to return a result or throw checked exceptions. Suitable for tasks that are more complex and require a return value or need to handle potential exceptions during execution.

    Example:

    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<Integer> future = executor.submit(new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            return 456;
        }
    });
    
    try {
        Integer result = future.get();
        System.out.println("Callable task result: " + result);
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    } finally {
        executor.shutdown();
    }

Conclusion

Both Runnable and Callable are used to represent tasks in Java, but they serve different purposes. Runnable is simpler and is used when no result or checked exception handling is needed. Callable is more versatile, providing a way to return results and handle exceptions. Understanding these differences helps you choose the appropriate interface for your concurrent task execution needs.

Recent job openings