skip to content

What is an intrinsic lock (monitor) in Java, and how does synchronized use it?

level: middleimportance: must knowfreq 70%

answer

  1. One intrinsic lock (monitor) per object — free, invisible
  2. synchronized is the only way to acquire it
  3. Acquire on enter, release on exit (even on exception)
  4. Release→acquire gives happens-before (visibility)
  5. Backs wait/notify; must hold monitor to call them

basics

~20 s

Every Java object has one built-in lock called its intrinsic lock or monitor. The synchronized keyword acquires that lock when a thread enters the region and releases it when the thread leaves, so only one thread at a time can hold it.

solid answer

~40 s

Every object in Java owns a single intrinsic lock, also called its monitor. You don't allocate it — it exists for every object and even every Class object. synchronized is the only way to use it: entering a synchronized method or block acquires the monitor of the designated object; exiting (normally or via exception) releases it. Because only one thread can hold a given monitor at a time, this gives mutual exclusion across all regions guarded by that same object. Beyond mutual exclusion, acquiring and releasing the monitor establishes a happens-before relationship under the Java Memory Model, so writes made by the previous holder become visible to the next thread that acquires the same lock. The monitor also backs wait()/notify()/notifyAll(), which a thread may call only while holding that object's monitor.

go deeper

for a junior

Knows the slogan 'every object has a lock' and that synchronized uses it so only one thread runs the code at once.

for a middle

Explains acquire-on-enter/release-on-exit, that the same-object lock is what serializes regions, and that the monitor backs wait/notify.

for a senior

Connects the monitor to the Java Memory Model's happens-before edge for visibility and reasons about both atomicity and stale reads.

for a principal

Discusses JVM lock implementation (biased/thin/inflated locks, hold counts), the cost of inflation/contention, and when to replace intrinsic locks with j.u.c primitives for fairness, timeouts, or condition flexibility.

## What 'monitor' means A *monitor* is a classic concurrency construct: an object that combines mutual exclusion (a lock) with the ability to wait for and signal conditions. In Java this is built into the language: **every object has exactly one intrinsic lock**, also called its *monitor lock* or just *monitor*. You never declare or allocate it — it is an invisible property of every object instance and of every `Class` object. ## How synchronized uses it `synchronized` is the *only* construct that touches the intrinsic lock. When a thread: - enters `synchronized(obj){...}` (or a synchronized method whose lock is `obj`), it **acquires** `obj`'s monitor; - leaves that region — by reaching the end, returning, or throwing an exception — it **releases** the monitor. At most one thread can hold a given object's monitor at any instant. A second thread that tries to acquire it **blocks** (waits) until the holder releases it. This is *mutual exclusion*: all synchronized regions that lock on the **same** object are serialized with respect to each other. ## Two roles of the monitor 1. **Mutual exclusion** — only one holder at a time, as above. 2. **Memory visibility (happens-before).** Under the *Java Memory Model* (the rules that say which writes one thread is guaranteed to see in another), releasing a monitor *happens-before* a subsequent acquire of the **same** monitor. Practically: everything the releasing thread wrote before unlocking is guaranteed visible to the next thread that locks the same monitor. Without synchronization (or `volatile`), one thread might never see another's writes, or see them out of order. So `synchronized` provides both atomicity *and* visibility — a point many people miss. ## Condition queues: wait / notify The monitor also owns a *wait set*. `obj.wait()`, `obj.notify()`, and `obj.notifyAll()` may be called **only by a thread that currently holds `obj`'s monitor** — otherwise you get `IllegalMonitorStateException`. `wait()` atomically releases the monitor and parks the thread; `notify`/`notifyAll` wake waiting threads, which must then re-acquire the monitor before proceeding. This is how threads coordinate ('wait until the queue is non-empty'). ## Reentrancy Intrinsic locks are *reentrant*: a thread that already holds a monitor can acquire it again (e.g. one synchronized method calling another on the same object) without deadlocking itself. The JVM tracks a hold count, decrementing on each exit and releasing only when it reaches zero. ## Summary The intrinsic lock is the foundation of Java's built-in concurrency: one per object, used exclusively through `synchronized`, providing mutual exclusion, memory-visibility guarantees, reentrancy, and the wait/notify condition mechanism.

  • Besides mutual exclusion, what guarantee does acquiring/releasing an intrinsic lock provide?
    Memory visibility via a happens-before edge: writes made before a thread releases a monitor are visible to the next thread that acquires the same monitor. So synchronized fixes both atomicity and stale-read problems.
  • What happens if you call obj.wait() without holding obj's monitor?
    You get an IllegalMonitorStateException. wait/notify/notifyAll require the calling thread to currently own that object's monitor.

saying these in an interview costs you the question

  • Saying synchronized only prevents simultaneous execution but ignoring its memory-visibility (happens-before) guarantee.
  • Thinking you allocate or new-up a monitor — it already exists on every object.
  • Believing different synchronized blocks always exclude each other regardless of lock object — only same-object locks exclude.
  • Calling wait/notify from outside a synchronized region holding that object's monitor.

context