Java / Java Concurrency and Multi Threading in Java 17 and Java 21 Interview questions
Explain the internal working of AbstractQueuedSynchronizer (AQS)?
AbstractQueuedSynchronizer is the framework that most of java.util.concurrent's locks and synchronizers, including ReentrantLock, Semaphore, CountDownLatch, and ReentrantReadWriteLock, are built on top of, so understanding it explains how they all share consistent, correct behavior.
flowchart LR
A[acquire called] --> B{tryAcquire succeeds?}
B -- Yes --> C[Thread proceeds, holds state]
B -- No --> D[Thread enqueued in CLH-style wait queue]
D --> E[Thread parked]
F[release called] --> G[Head of queue unparked]
G --> B
At its core, AQS holds a single volatile int state field, and subclasses define what that number means: for ReentrantLock it's the hold count (0 means unlocked, and it increments per reentrant acquisition by the owning thread); for Semaphore it's the number of available permits; for CountDownLatch it's the remaining count.
A thread trying to acquire calls a subclass-defined tryAcquire, which attempts to update state with CAS. If that fails, meaning the resource is unavailable, AQS enqueues the thread as a node in an internal CLH-style (Craig, Landin, and Hagersten) doubly linked wait queue and parks it using LockSupport.park(), which is cheaper than a full OS-level block for a monitor.
When release is called and it updates state to indicate the resource is available again, AQS unparks the thread at the head of the wait queue, which then retries tryAcquire. This shared queue-and-CAS design is why all these different synchronizers behave predictably under contention despite representing very different concepts.
More Related questions...