Difference Between Runnable and Callable
Runnable and Callable both describe a task that can run on another thread. Runnable has a run() method that returns nothing and can't throw checked exceptions. Callable<V> has a call() method that returns a value and may throw any exception. Runnable dates from Java 1.0; Callable was added in Java 5 with the Executor framework. In this lesson, you will compare them side by side.
Example: The Same Job Both Ways
Let's see an example that counts the vowels in a name, once as a Runnable and once as a Callable.
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
public class RunnableVsCallable {
static int vowels(String s) {
return (int) s.toLowerCase().chars()
.filter(c -> "aeiou".indexOf(c) >= 0).count();
}
public static void main(String[] args) throws Exception {
try (ExecutorService pool = Executors.newSingleThreadExecutor()) {
AtomicInteger holder = new AtomicInteger();
Runnable r = () -> holder.set(vowels("Anamaneni"));
pool.submit(r).get();
System.out.println("Runnable stored: " + holder.get());
Callable<Integer> c = () -> vowels("Anamaneni");
Future<Integer> f = pool.submit(c);
System.out.println("Callable returned: " + f.get());
Callable<String> reader = () -> {
throw new java.io.IOException("file not found");
};
try {
pool.submit(reader).get();
} catch (java.util.concurrent.ExecutionException e) {
System.out.println("Callable threw: " + e.getCause());
}
}
}
}Runnable stored: 5
Callable returned: 5
Callable threw: java.io.IOException: file not foundExplanation: The Runnable can't return its answer, so it stores it in a shared AtomicInteger. The Callable simply returns it, and the result arrives through the Future. The last Callable throws a checked IOException, which a Runnable couldn't do without wrapping it.
Differences Between Runnable and Callable
Runnable | Callable<V> | |
|---|---|---|
| Package | java.lang | java.util.concurrent |
| Introduced | Java 1.0 | Java 5 |
| Method | void run() | V call() throws Exception |
| Returns a result | No | Yes |
| Checked exceptions | Can't throw them | Can throw them |
Run by a plain Thread | Yes: new Thread(runnable) | No: needs an executor or FutureTask |
| Submitted to an executor | execute or submit | submit, invokeAll, invokeAny |
Which One Is a Lambda?
Common Mistakes
Passing a Callable to new Thread(...). It doesn't compile; wrap it in a FutureTask or use an executor.
Using a shared variable to get a result from a Runnable. Use a Callable and its Future instead.
Interview Corner
What is the difference between Runnable and Callable?
Runnable.run() returns void and can't throw checked exceptions; it can be run by a Thread or an executor. Callable<V>.call() returns a value of type V and can throw checked exceptions; it's submitted to an ExecutorService, which returns a Future<V> for the result or the failure. Use Callable whenever the task produces a result or may fail with a checked exception.
Practice
- Easy: Rewrite a
Runnablethat prints a square number as aCallable<Integer>that returns it. - Harder: Wrap a
Callablein aFutureTask, run it with a plainThread, and read the result from theFutureTask.
Key Takeaways
Was this tutorial helpful?