Thread vs Runnable vs Callable
Fast recall
Quick revision
Core answer
Whether the candidate understands Java's concurrency primitives and can choose the right abstraction for the task.
Confusing Callable with Runnable — Callable can return a value and throw checked exceptions; Runnable cannot.
Mention that Thread itself implements Runnable, and discuss how Callable integrates with ExecutorService via Future/FutureTask.
Interview-ready guide
Interview answer
Java provides three ways to represent a concurrent task: extending Thread, implementing Runnable, or implementing Callable. In modern Java, extending Thread directly is considered legacy — tasks are expressed as Runnable or Callable and submitted to an ExecutorService, which manages threads as a pool.
Three approaches:
- Extending Thread: wastes your single inheritance slot; can't be submitted to ExecutorService — legacy only
Runnable:run()returns void, cannot throw checked exceptions — for fire-and-forget tasksCallable:call()returns a value, can throw checked exceptions — submit to get aFuture
Both are functional interfaces:
- Expressible as lambdas — compiler infers which based on whether the lambda returns a value
executor.execute(() -> doWork())vsFuturef = executor.submit(() -> compute())
Beyond Future:
Future.get()blocks the calling thread —CompletableFutureis the modern upgrade with non-blocking composition, error handling, and chaining
I recommend Callable with CompletableFuture for most production scenarios. Never create Thread objects directly.
Thread vs Runnable vs Callable
Direct Answer
Runnable is the preferred low-level task abstraction (no return value, no checked exceptions). Callable is used when you need a return value or need to propagate checked exceptions. Extending Thread is discouraged because it tightly couples task logic to thread lifecycle.
Deep Dive & Architecture
A thread is an independent path of execution within a JVM process, sharing heap memory but having its own stack and program counter.
Java threads are 1:1 mapped to OS native threads on all mainstream JVMs (HotSpot, OpenJ9) — each platform thread costs ~0.5–1 MB of stack memory and is scheduled by the OS.
Runnable is the preferred low-level task abstraction (no return value, no checked exceptions). Callable is used when you need a return value or need to propagate checked exceptions. Extending Thread is discouraged because it tightly couples task logic to thread lifecycle.
Thinking threads have separate memory — they share heap. Calling thread.run() instead of thread.start() and wondering why everything runs on the main thread
Common Mistakes & Pitfalls
Confusing Callable with Runnable — Callable can return a value and throw checked exceptions; Runnable cannot.
Check your understanding
Answer these without looking back at the article.
- What are the different states in a Java thread's lifecycle?
- What are daemon threads in Java and how do they differ from user threads?
- How does thread interruption work in Java? Explain `interrupt()`, `isInterrupted()`, and `interrupted()`, and the correct way to respond to interrupts.
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.