Detailed explanation
Thread.sleep() and Object.wait() both suspend the current thread, but they solve different problems. sleep() is a static Thread method used to delay execution for a specified duration. wait() is an Object instance method used for coordination: a thread waits for a condition that another thread may establish. The main interview distinction is monitor ownership: sleep() does not release any monitor locks, whereas wait() releases the monitor of the object on which it is called.
Thread.sleep(1000) requests a pause of approximately one second, but it does not guarantee execution resumes exactly then; scheduling may delay the thread further. It requires no synchronized block. If called while holding a monitor, that monitor remains locked, so threads needing it cannot enter their synchronized sections during the sleep. Because sleep() is static, it always affects the calling thread, even if written through a Thread instance reference. A positive-duration sleep places the thread in TIMED_WAITING, unless interrupted.
For lock.wait(), the calling thread must own lock's monitor, normally through synchronized(lock); otherwise, Java throws IllegalMonitorStateException. Waiting atomically places the thread in that object's wait set and releases its monitor, while retaining any other locks the thread holds. wait() without a timeout enters WAITING; wait(1000) uses a bounded wait and enters TIMED_WAITING. Waiting may end through notify(), notifyAll(), interruption, timeout, or a spurious wakeup. Before returning normally or throwing InterruptedException, the thread must reacquire the same monitor. Notification therefore does not immediately let it continue, and the timeout does not bound the time needed to reacquire the monitor.
Correct waiting checks a shared condition in a loop: synchronized(lock) { while (!ready) { lock.wait(); } }. The notifying thread updates ready under the same monitor and calls notifyAll() or, when appropriate, notify(). The loop handles spurious wakeups and cases where another thread changes the condition before the awakened thread reacquires the lock. Both sleep() and wait() can throw InterruptedException, which clears the interrupt status; interruption should be propagated or handled deliberately. Interviewers expect more than the lock-release rule: explain monitor ownership, condition-based coordination, and why sleeping is not a reliable replacement for synchronization.
Key points to remember
- sleep() delays the current thread; wait() supports condition-based coordination.
- sleep() retains all held locks; wait() releases only the target object's monitor.
- wait() requires ownership of the target monitor; sleep() has no monitor-ownership requirement.
- wait() can end through notification, timeout, interruption, or spurious wakeup, but must reacquire the monitor before continuing.
- Use wait() inside a condition-checking while loop, and handle InterruptedException deliberately for both methods.
Common mistakes candidates make
- Saying wait() releases every lock held by the thread, rather than only the target object's monitor.
- Calling wait() without owning the correct monitor, or using an if check instead of a while loop.
- Assuming notify() immediately transfers the lock or that either method guarantees an exact resumption time.
Likely follow-up questions
What is the difference between notify() and notifyAll()?
notify() selects one arbitrary thread from the object's wait set, while notifyAll() wakes all threads in that wait set. Each awakened thread must reacquire the monitor and recheck its condition; neither method releases the notifier's lock immediately.
Why must wait() be called inside a while loop?
A thread can wake spuriously, and notification does not guarantee that its condition is still true when it reacquires the monitor. The while loop rechecks the condition and waits again if necessary.
What should you do when sleep() or wait() throws InterruptedException?
Usually, propagate the exception if the method contract allows it. If you cannot propagate it, restore the interrupt status with Thread.currentThread().interrupt() and return or follow the application's cancellation policy rather than silently ignoring it.
Interview tip: Start with purpose and lock behaviour, then use a synchronized example to explain monitor ownership, the condition loop, and reacquisition.
