synchronized Monitor Inflations vs ReentrantLock (AQS)
- Last updated
- Prerequisites:
- Java threads and synchronization basics
- Understanding of locks and condition variables
- java
- synchronized
- reentrantlock
- aqs
- monitor
- locking
- concurrency
Read at your depth
The practical view
synchronized blocks/methods use intrinsic monitors: automatic, concise, and reentrant (the same thread can re-acquire). ReentrantLock offers more: tryLock(timeout), lockInterruptibly(), fair locking, and Condition objects (await/signal instead of wait/notify). Both are reentrant. Performance is similar in modern JVMs; choose synchronized for simplicity and ReentrantLock when you need timeout/try-lock/interruptibility/fairness/multiple conditions. Always release ReentrantLock in finally (unlock), whereas synchronized releases automatically.
The same idea in other frameworks
N/A — JVM concurrency concern.N/A — JVM concern.N/A — JVM concern.N/A — JVM concern.Legacy vs modern
synchronized timeout problem vs ReentrantLock tryLock
synchronized cannot time out or be interrupted while waiting; ReentrantLock.tryLock(timeout) gives bounded waits, but requires manual unlock.
synchronized (lock) {
// ❌ OLD: if another thread holds the lock forever, this blocks forever
}if (lock.tryLock(2, TimeUnit.SECONDS)) { try { ... } finally { lock.unlock(); } } // ✅ NEWInterview gotchas
Context
This tests the monitor mechanics — interviewers want the thin-lock → heavyweight transition and why uncontended synchronized is cheap, not just 'synchronized uses the monitor'.
The mechanical answer
An uncontended synchronized block performs a thin-lock fast path: a single CAS on the object header's mark word, typically by the interpreter/JIT with no OS involvement — very cheap. When contention occurs (another thread tries to acquire), the lock 'inflates' to a heavyweight ObjectMonitor: the mark word is replaced with a pointer to the monitor structure, which manages an owner field, entry queues (cxq/EntryList), and a wait set for wait/notify. Inflated monitors park blocked threads via the OS (LockSupport/mutex), which is expensive. Since JDK 15, biased locking is removed, so there is no biased-lock acquisition; the fast path is thin-lock CAS, and the slow path is the inflated monitor. This design is why synchronized scales well when uncontended and degrades under heavy contention like any parking-based lock.
Trap
The naive answer is 'synchronized is always heavyweight'. It's thin until contention inflates it. Another trap: assuming synchronized and ReentrantLock have identical semantics — both are reentrant, but ReentrantLock adds timeout/interrupt/fairness/conditions, and synchronized's wait/notify requires holding the monitor (with spurious-wakeup caveats). Candidates who describe the mark word and inflation path show real JVM understanding.
Context
This probes the queue-based synchronizer design — interviewers want the volatile state + CLH queue + park/unpark model that underlies most of java.util.concurrent.
The mechanical answer
AQS maintains a single volatile int state and a doubly-linked FIFO wait queue of Node objects. For ReentrantLock (exclusive mode): lock() calls acquire(1), which tries compareAndSetState(0→1); on failure, it enqueues a Node (CAS the tail) and parks the thread via LockSupport.park, looping until it wins. unlock() calls release(1): setState to 0 and unpark the successor node's thread. Reentrancy is handled by counting: acquire increments state per re-acquisition, release decrements. Fair mode checks whether the queue has waiting predecessors before barging; non-fair (default) attempts a CAS first (barging). Conditions are separate ConditionObject queues: await() releases state and parks on the condition queue; signal() transfers one node to the sync queue. The same AQS framework implements Semaphore (shared mode), CountDownLatch, and ReadWriteLock.
Trap
The naive answer is 'AQS is a lock implementation'. It's a framework for building synchronizers; ReentrantLock is one use of it. Another trap: thinking park/unpark is a spin — it's an OS-level thread park (futex-like), and fairness isn't the default. Candidates who name the state machine, the CLH queue, and the shared/exclusive modes show real depth.