skip to content

What does Thread.sleep() do, and how does it differ from Object.wait() regarding locks?

level: juniorimportance: must knowfreq 78%

answer

  1. sleep keeps locks; wait releases the monitor
  2. sleep is static (current thread); wait is on an object
  3. both throw InterruptedException; state = TIMED_WAITING for sleep
  4. wait must be held under synchronized; wakes via notify
  5. sleep may overrun the requested time, never under

basics

~10 s

Thread.sleep() pauses the current thread for a given time but keeps any locks it holds. wait() also pauses the thread but releases the lock on the object so other threads can use it.

solid answer

~40 s

Thread.sleep(ms) makes the currently executing thread pause for at least the given milliseconds, putting it in TIMED_WAITING state. Crucially, sleep does NOT release any monitor locks the thread holds — so calling sleep inside a synchronized block keeps everyone else blocked. Object.wait(), by contrast, must be called while holding the object's monitor and atomically releases that monitor while the thread waits, letting other threads enter the synchronized region; the thread re-acquires the lock when notified. So sleep is a pure timed pause unrelated to coordination, while wait/notify is a coordination primitive tied to a lock. sleep is static (acts on the current thread), throws InterruptedException, and the actual pause may be longer than requested due to scheduling.

go deeper

for a junior

Knows sleep pauses the current thread for a time and keeps locks, while wait releases the lock.

for a middle

Explains the TIMED_WAITING state, that sleep is static and lock-agnostic, and that wait/notify is a coordination primitive requiring the monitor.

for a senior

Discusses why sleeping under a lock serializes threads, spurious wakeups, InterruptedException handling, and prefers higher-level concurrency utilities over raw wait/notify.

for a principal

Frames sleep vs wait in terms of designing coordination: avoids busy-wait/sleep-polling patterns, reasons about liveness and lock contention, and steers teams to BlockingQueue/Condition/CompletableFuture.

## Threads and pausing A **thread** is an independent path of execution inside a program. The JVM can run many threads, and the OS **scheduler** decides which thread runs on a CPU core at any moment. Sometimes you want a thread to stop running for a while — to wait, to slow down a loop, to back off and retry. ## What `Thread.sleep` does `Thread.sleep(long millis)` is a **static** method, meaning it always acts on **the thread that calls it** (the *currently executing* thread). It tells the scheduler: "don't run me again for at least `millis` milliseconds." During that time the thread is in the **`TIMED_WAITING`** state (one of Java's thread states, meaning it is paused but will wake up on its own after a timeout). After the time elapses the thread becomes **`RUNNABLE`** again, but it does not necessarily run *immediately* — it just becomes eligible. So the real pause can be **longer** than requested (never shorter on a correct JVM). ```java Thread.sleep(1000); // pause this thread ~1 second ``` ## A lock / monitor — the key term In Java, every object has an associated **monitor** (also called an *intrinsic lock*). A `synchronized` block or method **acquires** that monitor on entry and **releases** it on exit, guaranteeing only one thread is inside the protected region at a time. ## The critical difference: sleep keeps locks `sleep` is **lock-agnostic**: if the sleeping thread is currently inside a `synchronized` block, it **keeps holding the monitor the whole time it sleeps**. No other thread can enter that synchronized region until the sleeper wakes up *and* exits the block. This is a common bug — sleeping while holding a lock serializes everyone. `Object.wait()` is different. It is an instance method that **must** be called while you already hold that object's monitor (else you get `IllegalMonitorStateException`). `wait()` **atomically releases** the monitor and parks the thread; another thread can now enter the synchronized region, change state, and call `notify()`/`notifyAll()` on the same object to wake the waiter. When the waiter wakes, it **re-acquires** the monitor before continuing. So `wait/notify` is a **coordination** mechanism ("wait until a condition holds"), whereas `sleep` is just a **timed pause**. ## Other differences - `sleep` is **static** (`Thread.sleep`), `wait` is an **instance** method on any object. - Both throw **`InterruptedException`** — another thread can call `interrupt()` to wake them early; you must handle that checked exception. - `wait` typically lives in a **loop** that re-checks the condition (to guard against *spurious wakeups* — waking with no notification). `sleep` does not need that. ## When to use which Use `sleep` for back-off, polling delays, simple timing — but **never while holding a lock you don't need**. Use `wait/notify` (or higher-level tools like `BlockingQueue`, `Condition`, `CountDownLatch`) when a thread must wait for *another* thread to make a condition true.

  • Why is calling Thread.sleep() inside a synchronized block often a bug?
    Because sleep does not release the monitor, every other thread that needs that lock is blocked for the entire sleep duration, killing concurrency. If you must wait, use wait() or move the sleep outside the lock.
  • Can sleep wake up earlier than its timeout?
    Yes — if another thread interrupts it, sleep throws InterruptedException immediately. Otherwise it sleeps at least the requested time (often slightly more), never less voluntarily.

saying these in an interview costs you the question

  • Claiming sleep() releases locks — it does not; only wait() does.
  • Saying sleep guarantees the exact duration — it's a minimum, and can overrun due to scheduling.
  • Thinking wait() can be called without holding the monitor — that throws IllegalMonitorStateException.
  • Confusing sleep (static, current thread) with calling sleep on a specific thread object.

context