Runnable, Callable, and Thread Lifecycle
Runnable vs Callable
Runnable |
Callable<V> |
|
|---|---|---|
| Package | java.lang |
java.util.concurrent |
| Method | void run() |
V call() throws Exception |
| Return value | None | Returns V |
| Checked exceptions | Not allowed | Allowed |
Use with Thread |
Yes | No (wrap or use ExecutorService) |
Use with ExecutorService |
Yes | Yes |
javaRunnable r = () -> System.out.println("runnable — no return");
Callable<Integer> c = () -> {
Thread.sleep(100);
return 42;
};Creating Threads with Runnable
java// Pass to Thread constructor
Thread t = new Thread(() -> System.out.println("hello"));
t.start();
// Subclassing Thread (less common)
class MyThread extends Thread {
public void run() {
System.out.println("subclass");
}
}
new MyThread().start();Exam tip: Calling
t.run()directly does NOT start a new thread — it executes on the calling thread. Always uset.start().
Using Callable with ExecutorService
Thread does not accept Callable directly. Use an ExecutorService to submit a Callable and retrieve the result through a Future<V>.
javaExecutorService exec = Executors.newSingleThreadExecutor();
Future<Integer> future = exec.submit(() -> 7 * 6); // Callable<Integer>
Integer result = future.get(); // blocks until done → 42
exec.shutdown();Thread Lifecycle
plaintextNEW → RUNNABLE → (BLOCKED | WAITING | TIMED_WAITING) → TERMINATED
| State | Description |
|---|---|
NEW |
Thread created but start() not yet called |
RUNNABLE |
Running or ready to run (waiting for CPU) |
BLOCKED |
Waiting to acquire a monitor lock (synchronized) |
WAITING |
Waiting indefinitely: Object.wait(), Thread.join(), LockSupport.park() |
TIMED_WAITING |
Waiting with a timeout: Thread.sleep(ms), Object.wait(ms), Thread.join(ms) |
TERMINATED |
run() has completed or thrown an uncaught exception |
javaThread t = new Thread(() -> {});
System.out.println(t.getState()); // NEW
t.start();
// after completion:
System.out.println(t.getState()); // TERMINATEDThread.sleep()
Pauses the current thread for at least the given duration. The thread moves to TIMED_WAITING.
javaThread.sleep(500); // milliseconds
Thread.sleep(Duration.ofSeconds(1)); // Duration overload (Java 21+)sleep() throws InterruptedException if another thread interrupts the sleeping thread. Always handle it.
javatry {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore interrupted status
}join()
Causes the calling thread to wait until the target thread finishes.
javaThread worker = new Thread(() -> heavyComputation());
worker.start();
worker.join(); // main thread waits here
worker.join(5000); // wait at most 5 seconds
System.out.println("worker done");interrupt(), isInterrupted(), interrupted()
| Method | Description |
|---|---|
t.interrupt() |
Sets the interrupted flag on thread t; if t is sleeping/waiting, throws InterruptedException |
t.isInterrupted() |
Returns the interrupted flag without clearing it |
Thread.interrupted() |
Returns and clears the interrupted flag of the current thread |
javaThread worker = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
doWork();
}
System.out.println("stopped cleanly");
});
worker.start();
worker.interrupt(); // signals the worker to stopjava// Blocking methods throw InterruptedException — must restore flag
try {
Thread.sleep(10_000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore so callers can detect it
return;
}Exam tip:
Thread.interrupted()is static and clears the flag.isInterrupted()is instance-based and does not clear it.
Thread Priority
javathread.setPriority(Thread.MIN_PRIORITY); // 1
thread.setPriority(Thread.NORM_PRIORITY); // 5 (default)
thread.setPriority(Thread.MAX_PRIORITY); // 10Priority is a hint to the OS scheduler — it does not guarantee execution order.
Daemon Threads
javaThread daemon = new Thread(() -> monitorSystem());
daemon.setDaemon(true); // must be called before start()
daemon.start();The JVM exits when only daemon threads remain. Virtual threads are always daemon threads.
Key Rules
start()registers the thread with the JVM scheduler;run()executes synchronously on the caller.- A thread can only be started once — calling
start()a second time throwsIllegalThreadStateException. InterruptedExceptionclears the interrupted flag; always re-interrupt when catching it if you cannot handle it fully.CallablerequiresExecutorServiceor aFutureTaskwrapper to run on a thread.