Definition
Thread.stop()– forcibly throwsThreadDeathat an arbitrary point, releasing all monitors and leaving shared objects in a half-updated state.Thread.suspend()– freezes a thread without releasing its locks, so any thread needing those locks deadlocks.Thread.resume()– deprecated because it only pairs with the unusablesuspend().- Correct replacement – cooperative interruption with
interrupt(), checkingisInterrupted()at safe points, and handlingInterruptedException. - For pausing – use
Object.wait()on a condition, which releases the lock while paused.
Imagine a teller at National Bank of India is halfway through a transfer: she has debited Rajesh but not yet credited Priya. stop is like dragging her away mid-transfer and throwing her keys on the floor: money vanishes and the drawer is unlocked. suspend is like freezing her in place while she clutches the vault key, so every other teller is stuck. The safe way is to pass her a note saying "please stop when you have finished the current transfer."
Understanding the Concepts
Why is Thread.stop() dangerous?
It throws ThreadDeath at whatever instruction the thread is executing. If the thread is between debit and credit, stop fires after the debit and before the credit. As the thread unwinds it releases all monitors, so other threads see the corrupted state as valid.
// The danger: stop fires between these two lines
synchronized (ledger) {
rajesh.debit(amount); // done
// ← ThreadDeath thrown here
priya.credit(amount); // never executed
} // lock released with inconsistent state
Why is Thread.suspend() dangerous?
It pauses the thread immediately but does not release any locks it holds. If the suspended thread holds the ledger lock and the resuming thread needs it, deadlock results.
// Thread A holds the lock and is suspended
synchronized (ledger) {
// ← suspended here, lock NOT released
}
// Thread B tries to acquire the same lock to call resume
synchronized (ledger) { // DEADLOCK: lock held by frozen Thread A
threadA.resume();
}
What is the correct replacement for stop?
Cooperative interruption. The controller calls interrupt(), the worker checks the flag only between complete operations.
package com.bank.worker;
public class TransferWorker implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
doOneTransfer(); // interruption can only take effect between transfers
}
System.out.println("Stopped between transfers, ledger is consistent.");
}
}
What is the correct replacement for suspend/resume?
A guarded wait on a condition that releases the lock while paused.
package com.bank.worker;
public class PausableWorker implements Runnable {
private volatile boolean paused = false;
private final Object pauseLock = new Object();
public void pause() { paused = true; }
public void resumeWork() {
synchronized (pauseLock) {
paused = false;
pauseLock.notifyAll();
}
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
synchronized (pauseLock) {
while (paused) {
try {
pauseLock.wait(); // releases the lock while paused
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
doOneTransfer();
}
}
}
What are the key differences?
| Method | Problem | Safe Replacement |
|--------|---------|------------------|
| stop() | Inconsistent state, released locks | interrupt() + check at safe point |
| suspend() | Deadlock: holds locks while frozen | wait() releases lock while paused |
| resume() | Only pairs with broken suspend() | notifyAll() |
What should a senior engineer know?
ThreadDeath is a Throwable that can be caught, leading to even weirder behaviour where a thread refuses to die. Forced control over another thread is never safe; cooperative signalling is the only correct approach.
What are common interview follow-up questions?
- Can ThreadDeath be caught to prevent stopping?
- How does ExecutorService.shutdownNow() use interrupt instead of stop?
- What happens if you call stop on a thread that has already exited?
Visual Overview
Thread.stop():
┌──────────────────────────────────┐
│ synchronized (ledger) { │
│ rajesh.debit(50000); ✓ done │
│ ←── ThreadDeath thrown here ──▶│ lock released
│ priya.credit(50000); ✗ skip │
│ } │
└──────────────────────────────────┘
Result: Rs.50000 vanished, ledger inconsistent
Thread.suspend():
┌──────────────────────────────────┐
│ Thread A: synchronized (ledger) │
│ ←── suspended, lock NOT freed │
│ │
│ Thread B: synchronized (ledger) │
│ ←── BLOCKED forever (deadlock) │
└──────────────────────────────────┘
Correct: cooperative interrupt
┌──────────────────────────────────┐
│ while (!isInterrupted()) { │
│ doOneTransfer(); // safe point│
│ } │
│ // stops only between transfers │
└──────────────────────────────────┘
Key Takeaway
Thread.stop, suspend, and resume are deprecated because they are inherently unsafe. Stop throws ThreadDeath at an arbitrary point and releases all monitors, leaving shared state inconsistent. Suspend freezes a thread without releasing its locks, causing deadlock.
The correct replacement is cooperative interruption. The controller calls interrupt(), and the worker checks the flag only between complete operations, so a stop can only take effect at a safe point. For pausing, use a guarded wait that releases the lock while paused.
At National Bank of India we inherited a worker killed with stop that left the ledger out of balance. The fix checked the interrupt flag only between complete transfer pairs, and a wait-based pause released the lock properly.
Remember one sentence: forced control over another thread is never safe, so signal with interrupt and let the thread stop itself at a point where its state is consistent.
---