Runnable Compatibility with Thread and ExecutorService
Fast recall
Quick revision
Core answer
Runnable can be given to a Thread and to Executor.execute or submit. execute returns no Future; an uncaught runtime exception is handled through the worker thread's uncaught-exception path. submit captures task failure in the returned Future, so it is observed when get() is called. Neither method should be described as silently swallowing every exception.Confirmation that the candidate understands Runnable's versatility and the abstraction between task definition and execution strategy
Not knowing ExecutorService also accepts Runnable—thinking it only takes Callable, or not understanding the difference between execute and submit
Explain that ExecutorService.submit returns Future even for Runnable, and clarify when to use execute versus submit
Interview-ready guide
Interview answer
Yes, absolutely.
A Runnable can go to the Thread constructor and to ExecutorService methods like execute and submit. That's one of the key design strengths of Runnable. It separates the task from how it runs.
You write the task once, then run it with a raw thread, with a pool, or submit it many times, without changing the task code. When you're learning, you might use new Thread with a Runnable and call start. But in production you'd almost always use an ExecutorService, because the pool reuses threads instead of creating a new one each time.
ExecutorService has two main methods for a Runnable. Execute is fire-and-forget and returns nothing. Submit also accepts a Runnable, but it returns a Future.
get returns null after a Runnable completes normally, but it's still useful. You can call get to wait for completion, or check isDone, or catch an exception that happened during execution. One gotcha to mention: a failure from execute is not delivered through a Future and instead follows the worker's uncaught-exception handling, so use submit and check the future to see it.
The same Runnable works everywhere, which is why it's a widely used task interface in Java.
Runnable Compatibility with Thread and ExecutorService
Direct Answer
A Runnable can be given to a Thread and to Executor.execute or submit. execute returns no Future; an uncaught runtime exception is handled through the worker thread's uncaught-exception path. submit captures task failure in the returned Future, so it is observed when get() is called. Neither method should be described as silently swallowing every exception.
Common Mistakes & Pitfalls
- Saying execute hides every exception: an uncaught failure follows the worker's uncaught-exception handling; the submitter simply receives no Future.
- Ignoring a Future from submit: task failures remain wrapped until code observes the Future.
- Saying Future.get is always null: it returns null only after normal completion of the usual Runnable submission; on failure or cancellation it throws.
- Assuming every executor is a thread pool: implementations include single-worker, scheduled, fork/join, and virtual-thread models.
- Forgetting shutdown: a component should stop an executor it owns according to its lifecycle.
Check your understanding
Answer these without looking back at the article.
- What is the difference between execute() and submit() on ExecutorService?
- What does Future.get() return for a Runnable submitted via submit()?
- Can you pass a lambda directly to executor.execute() without creating a named Runnable?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.