Card 03/ 09
Runnable vs Callable
The two ways to describe a task, and the two things only one of them can hand back.
Runnable and Callable are the two interfaces that describe a task for a thread or a pool. Both have one method and both can be written as a lambda; they differ in the two things a method can produce: a value, and a checked exception. Submitting either to a pool returns a Future, a handle for a result that arrives later.
| Compared on | Runnable | Callable<V> |
|---|---|---|
| The method | void run() | V call() throws Exception |
| Returns a value | No | Yes |
| May throw a checked exception | No | Yes |
| Submitting gives you | Future<?>, whose get() returns null when it completes | Future<V>, holding the result |
| Used by | Thread, execute, submit | submit, invokeAll |
Future<?> a = pool.submit(() -> log.info("done"));
Future<Long> b = pool.submit(() -> countRowsIn(file));The compiler chooses between them from the lambda's body. Line 1 produces nothing, so it is a Runnable; line 3 produces a long, so it is a Callable. Nothing in the source says which.
The decision rule. If the task produces an answer somebody wants, or can fail in a way somebody should hear about, it is a Callable. Otherwise Runnable is fine. The exception matters most, because a Callable's exception reaches whoever collects its result.
Where an exception from a Runnable goes depends on how it was handed to the pool. Through submit, it is caught and stored in the returned Future, like a Callable's. Through execute, it reaches the thread's uncaught-exception handler, which by default prints it to standard error and nothing else.
← → move through sections and cards