Definition
- InterruptedException – thrown when a thread is interrupted while blocked in
sleep(),wait(),take(),lock.lockInterruptibly(), or similar methods. - Flag clearing – catching the exception automatically sets the interrupt flag to false, erasing the signal.
- Restore the flag – call
Thread.currentThread().interrupt()inside the catch block so the caller or next loop iteration can detect the interruption. - Propagate – declare
throws InterruptedExceptionand let the caller decide how to respond. - Swallowing – catching InterruptedException and doing nothing breaks
shutdownNow(),Future.cancel(true), and all cooperative cancellation mechanisms.
At National Bank of India, the branch manager (shutdown signal) calls a teller (thread): "Stop, it is closing time!" The teller is processing a large batch (blocking call) when the phone rings (InterruptedException). Swallowing means the teller answers the phone, hears "stop," hangs up, and continues working. The manager can never reach the teller again. Restoring the flag means the teller answers, hears "stop," puts a sticky note on the desk saying "STOP REQUESTED," finishes the current item, checks the note, and exits gracefully.
Understanding the Concepts
What is InterruptedException?
InterruptedException is a checked exception thrown when a thread is in a blocking operation and another thread calls interrupt() on it. Blocking operations that throw InterruptedException include Thread.sleep(), Object.wait(), BlockingQueue.take(), Lock.lockInterruptibly(), and CountDownLatch.await().
The interrupt mechanism is Java's cooperative cancellation system. One thread signals another to stop by calling thread.interrupt(). The interrupted thread decides how to respond.
Why does catching InterruptedException clear the flag?
When Thread.interrupt() is called, it sets the thread's interrupt flag to true. If the thread is in a blocking call, the JVM throws InterruptedException and clears the flag back to false. The exception itself is the notification. But if you catch and ignore it, both the exception and the flag are gone. The thread has no way to know it was interrupted.
Thread.currentThread().interrupt(); // flag = true
try {
Thread.sleep(1000); // flag is true, so InterruptedException thrown immediately
} catch (InterruptedException e) {
// flag automatically cleared to false!
System.out.println("Interrupted: " + Thread.currentThread().isInterrupted());
// prints: Interrupted: false
}
What happens when you swallow InterruptedException?
Swallowing means catching the exception and doing nothing. The interrupt signal is permanently lost. All cooperative cancellation mechanisms break.
// WRONG: swallowing InterruptedException
while (running) {
try {
String trade = queue.take(); // blocks, interruptible
settleTrade(trade);
} catch (InterruptedException e) {
// SWALLOWED! Interrupt flag cleared.
// queue.take() in next iteration blocks FOREVER.
// shutdownNow() cannot stop this thread.
// Thread runs until JVM is killed with kill -9.
}
}
How do you correctly handle InterruptedException?
There are two correct responses: restore the interrupt flag, or propagate the exception.
package com.bank.service;
import java.util.concurrent.*;
public class InterruptHandling {
// Pattern 1: Restore flag and exit loop (service methods)
public void processSettlements(BlockingQueue<String> queue) {
while (!Thread.currentThread().isInterrupted()) {
try {
String trade = queue.take();
settleTrade(trade);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // RESTORE!
break; // exit gracefully
}
}
cleanup();
}
// Pattern 2: Propagate to caller (library methods)
public String fetchNextTrade(BlockingQueue<String> queue)
throws InterruptedException {
return queue.take(); // let caller decide
}
// Pattern 3: Restore flag in Runnable for thread pool
public Runnable createWorker(BlockingQueue<String> queue) {
return () -> {
try {
String trade = queue.take();
settleTrade(trade);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore for pool
return; // exit task
}
};
}
private void settleTrade(String trade) {
System.out.println("Settled: " + trade);
}
private void cleanup() {
System.out.println("Cleanup complete");
}
}
How does shutdownNow() use interrupts?
ExecutorService.shutdownNow() interrupts all worker threads. If tasks restore the interrupt flag or propagate the exception, the pool shuts down quickly. If tasks swallow the exception, workers continue indefinitely.
package com.bank.service;
import java.util.concurrent.*;
public class ShutdownDemo {
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(2);
pool.submit(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(100);
System.out.println("Processing...");
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // RESTORE
System.out.println("Interrupted, exiting");
}
}
});
Thread.sleep(350);
pool.shutdownNow(); // interrupts all workers
pool.awaitTermination(5, TimeUnit.SECONDS);
System.out.println("Pool terminated: " + pool.isTerminated());
}
}
Processing...
Processing...
Processing...
Interrupted, exiting
Pool terminated: true
What is the wrong way vs the right way to handle InterruptedException?
// WRONG: swallow and continue
catch (InterruptedException e) {
log.warn("Interrupted, continuing...");
// flag cleared, thread continues forever
}
// WRONG: wrap in RuntimeException without restoring flag
catch (InterruptedException e) {
throw new RuntimeException(e);
// flag not restored, upstream interrupt checks fail
}
// CORRECT: restore flag
catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore!
throw new RuntimeException("Interrupted during settlement", e);
}
// CORRECT: propagate
public void process() throws InterruptedException {
Thread.sleep(1000); // propagate naturally
}
What about Future.cancel(true) and interrupts?
Future.cancel(true) calls interrupt() on the thread running the task. If the task handles InterruptedException correctly (restores or propagates), cancellation works. If the task swallows it, cancellation fails.
Future<?> future = pool.submit(() -> {
try {
Thread.sleep(10000); // long task
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // restore for cancellation
System.out.println("Task cancelled, cleaning up");
}
});
Thread.sleep(100);
future.cancel(true); // interrupts the sleeping thread
What are common interview follow-up questions?
- What is the difference between
interrupt(),isInterrupted(), andThread.interrupted()?interrupt()sets the flag.isInterrupted()reads the flag without clearing.Thread.interrupted()reads and clears the flag. - Can you interrupt a thread that is not in a blocking call? Yes,
interrupt()sets the flag. The thread must checkisInterrupted()manually. - What happens if you call
interrupt()beforesleep()? The next call tosleep()throws InterruptedException immediately.
Visual Overview
Thread.interrupt() → Sets interrupt flag = true
│
▼
Thread in blocking call? (sleep, wait, take, lock)
│
┌───┴───┐
│ YES │ NO
▼ ▼
InterruptedException Flag stays true
thrown + flag cleared Thread must check
│ isInterrupted()
▼
┌─────────────────────────────────────┐
│ catch (InterruptedException e) │
│ │
│ WRONG: do nothing (swallow) │
│ → flag = false, signal lost │
│ → shutdownNow() broken │
│ │
│ RIGHT: restore flag │
│ Thread.currentThread().interrupt() │
│ → flag = true, signal preserved │
│ │
│ RIGHT: propagate │
│ throws InterruptedException │
│ → caller decides │
└─────────────────────────────────────┘
Key Takeaway
InterruptedException is Java's cooperative cancellation mechanism. When a thread is interrupted during a blocking call, the JVM throws InterruptedException and clears the interrupt flag. If you catch and ignore it, the signal is permanently lost. The thread becomes unkillable by normal means.
There are only two correct responses. For service methods with loops, restore the flag with Thread.currentThread().interrupt() and exit the loop. For library methods, propagate the exception with throws InterruptedException so the caller can decide. Never swallow it.
This matters because every shutdown mechanism in Java relies on interrupts. shutdownNow() interrupts all pool workers. Future.cancel(true) interrupts the running thread. If your task swallows the signal, the pool cannot shut down, cancellation fails, and the thread runs until the JVM is killed with kill -9. At National Bank of India, a settlement service swallowed InterruptedException, and deployment scripts could not stop it gracefully. Fifteen in-flight settlements were lost on force kill. After fixing the handler to restore the flag, the service exits in under 100 milliseconds with zero data loss.
Remember one sentence: never swallow InterruptedException, always restore the flag or propagate it.
---