Deep Dive into Java's AbstractQueuedSynchronizer (AQS) and Concurrency Utilities
This article provides a comprehensive explanation of Java's JUC origins, the design and implementation of AbstractQueuedSynchronizer (AQS), its template methods for exclusive and shared locks, the CLH queue mechanism, lock implementations, condition queues, and related code examples, illustrating how high‑performance concurrency primitives such as ReentrantLock, CountDownLatch, Semaphore, and ReentrantReadWriteLock work under the hood.
The article begins by describing the origin of JUC (Java Util Concurrent) as a response to the performance limitations of the synchronized keyword in early JDK versions, introducing the core component AbstractQueuedSynchronizer (AQS) that underlies many concurrency utilities.
It explains the template method pattern used by AQS, showing how subclasses implement abstract methods like tryAcquire , tryRelease , tryAcquireShared , and tryReleaseShared to define exclusive or shared lock behavior. Sample abstract class and concrete implementations are provided, with code wrapped in ... tags.
The article details the internal state management of AQS, including the volatile state field, CAS operations via compareAndSetState , and the role of the inner Node class. It enumerates the possible waitStatus values (CANCELLED, SIGNAL, CONDITION, PROPAGATE, INITIAL) and describes how the CLH (Craig, Landin, Hagersten) queue provides a FIFO ordering for threads waiting to acquire a lock.
Lock acquisition is broken down into the acquire method, which first attempts tryAcquire , then adds the thread to the queue with addWaiter , and finally spins in acquireQueued until the predecessor is the head node. The article also covers the shared‑mode acquisition path ( acquireShared , doAcquireShared ) used by constructs like CountDownLatch and Semaphore , highlighting the setHeadAndPropagate method for waking multiple successors.
Release operations are explained via release (exclusive) and releaseShared (shared), which invoke subclass‑implemented tryRelease or tryReleaseShared and then wake the next waiting thread using unparkSuccessor . The article also shows a custom lock implementation ( SowhatLock ) that demonstrates how to combine AQS with the Lock interface.
Further, the article introduces Condition objects, their separate wait queues, and the methods await , signal , and signalAll . It explains how a thread awaiting a condition releases the lock, moves to the condition queue, and later re‑enters the synchronization queue when signaled, with diagrams illustrating the transitions.
Finally, the piece provides references to additional reading on Java concurrency, including detailed analyses of Condition behavior and the internal workings of other synchronization utilities.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.