Java Notes
Complete guide to the Runnable interface in Java — functional interface, lambda usage, Callable vs Runnable, task encapsulation, sharing Runnables, and modern patterns with ExecutorService.
What is the Runnable Interface?
Runnable is a functional interface in java.lang package with a single abstract method run(). It represents a task that can be executed by a thread.
@FunctionalInterface
public interface Runnable {
void run();
}Why Runnable is Preferred Over Extending Thread
- Single inheritance: Your class can still extend another class
- Separation of concerns: Task logic is separate from threading
- Reusability: Same Runnable can be used with Thread, ExecutorService, etc.
- Composition: Multiple tasks can be composed together
- Testability: Easy to test without running in a separate thread
Basic Runnable Implementation
=== Runnable Interface Basic === [Thread-0] Download (1/5) [Thread-1] Upload (1/5) [Thread-0] Download (2/5) [Thread-1] Upload (2/5) [Thread-0] Download (3/5) [Thread-1] Upload (3/5) [Thread-0] Download (4/5) [Thread-1] Upload (4/5) [Thread-0] Download (5/5) [Thread-1] Upload (5/5) All tasks complete!
Runnable with Lambda Expressions
Since Runnable is a functional interface, lambdas make it concise:
=== Runnable with Lambdas === [Task-A] Working... 1 [Task-B] Working... 1 [Task-A] Working... 2 [Task-B] Working... 2 [Task-A] Working... 3 [Task-B] Working... 3 All lambda tasks done!
Runnable vs Callable
Java 5 introduced Callable<V> — a Runnable that can return a value and throw exceptions:
=== Runnable vs Callable === Runnable: void return, no checked exceptions Callable result: 120 (can return values!) Callable can throw checked exceptions.
Composing Runnables
public class RunnableComposition {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== Composing Runnables ===\n");
// Individual tasks
Runnable validate = () -> System.out.println(" 1. Validating input...");
Runnable process = () -> System.out.println(" 2. Processing data...");
Runnable save = () -> System.out.println(" 3. Saving results...");
Runnable notify = () -> System.out.println(" 4. Sending notification...");
// Compose into a pipeline
Runnable pipeline = compose(validate, process, save, notify);
System.out.println("Running pipeline on new thread:");
Thread t = new Thread(pipeline, "Pipeline");
t.start();
t.join();
System.out.println("\nRunning pipeline on main thread:");
pipeline.run();
}
// Utility: compose multiple Runnables into one
static Runnable compose(Runnable... tasks) {
return () -> {
for (Runnable task : tasks) {
task.run();
}
};
}
}Output:
Real-World Example: Task Queue
=== Task Queue with Runnables === Tasks queued: 5 [pool-1-thread-1] Executing Task-1 [pool-1-thread-2] Executing Task-2 [pool-1-thread-1] Executing Task-3 [pool-1-thread-2] Executing Task-4 [pool-1-thread-1] Executing Task-5 All tasks processed!
Common Mistakes
1. Confusing Runnable execution
Runnable task = () -> System.out.println("Thread: " + Thread.currentThread().getName());
// ❌ This does NOT create a new thread
task.run(); // Runs on current thread
// ✅ This creates a new thread
new Thread(task).start();2. Modifying shared state without synchronization
Interview Questions
Q1: What is the Runnable interface?
Answer: Runnable is a functional interface in java.lang with a single method void run(). It represents a task to be executed by a thread. Since Java 8, it can be implemented using lambda expressions.
Q2: Why is Runnable preferred over extending Thread?
Answer: (1) Allows extending another class (Java lacks multiple inheritance), (2) separates task logic from thread management, (3) same Runnable works with Thread, ExecutorService, ForkJoinPool, (4) promotes composition and reusability, (5) easier to test.
Q3: What is the difference between Runnable and Callable?
Answer: Runnable's run() returns void and cannot throw checked exceptions. Callable's call() returns a generic type V and can throw Exception. Callable is used with ExecutorService to get Future objects containing results.
Q4: Can a Runnable be reused across multiple threads?
Answer: Yes! A single Runnable instance can be passed to multiple Thread constructors. Each thread will execute the same run() method independently. However, if the Runnable has mutable state, proper synchronization is needed.
Q5: Is Runnable a functional interface?
Answer: Yes. It has exactly one abstract method (run()), making it usable with lambda expressions and method references since Java 8. Example: Runnable r = () -> System.out.println("Hello");
Q6: Why is Runnable a functional interface?
A: Runnable has exactly one abstract method (run()), making it a functional interface annotated with @FunctionalInterface. This means it can be implemented using lambda expressions or method references in Java 8+: new Thread(() -> doWork()).start(). This dramatically reduces boilerplate for simple thread tasks.
Q7: Can a single Runnable instance be shared among multiple threads?
A: Yes! Unlike extending Thread (where each instance IS a thread), a single Runnable can be passed to multiple Thread constructors. All threads execute the same run() method. This is useful for tasks that share resources, but requires synchronization if the Runnable has mutable state.
Q8: How does Runnable work with ExecutorService?
A: ExecutorService accepts Runnable tasks via execute(Runnable) or submit(Runnable). The executor manages a thread pool — your Runnable runs on a pooled thread instead of creating new threads. submit() returns a Future<?> for tracking completion (though Runnable doesn't return a value).
Q9: What is the difference between Runnable and Callable?
A: Runnable: void run() — no return value, cannot throw checked exceptions. Callable: V call() throws Exception — returns a value of type V, can throw checked exceptions. Use Callable when you need to get a result back from the thread (via Future.get()).
Q10: How do you convert a Runnable to a Callable?
A: Use Executors.callable(runnable) which returns a Callable that returns null. Or Executors.callable(runnable, result) which returns a specified result. You can also wrap manually: () -> { runnable.run(); return result; }.
Q11: Is Runnable's run() method thread-safe?
A: The run() method itself has no built-in thread safety. If the Runnable accesses shared mutable state, YOU must provide synchronization (synchronized blocks, volatile, Atomic classes, etc.). Runnable is just a task definition — thread safety is the developer's responsibility.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Runnable Interface in Java.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, multithreading, runnable, interface
Related Java Master Course Topics