Fundamentals 18 min read

Understanding Java's AbstractQueuedSynchronizer (AQS) Framework and Its Source Code

This article provides a comprehensive overview of Java's AbstractQueuedSynchronizer (AQS), explaining its design, exclusive and shared synchronization modes, key methods such as acquire, release, and their implementations, and demonstrates a simple Mutex application with detailed code analysis.

Qunar Tech Salon
Qunar Tech Salon
Qunar Tech Salon
Understanding Java's AbstractQueuedSynchronizer (AQS) Framework and Its Source Code

When discussing concurrency in Java, ReentrantLock inevitably leads to AbstractQueuedSynchronizer (AQS), an abstract queue‑based synchronizer that forms the backbone of many synchronization utilities such as ReentrantLock, Semaphore, and CountDownLatch.

AQS maintains a volatile int state representing the shared resource and a FIFO wait queue for threads that cannot acquire the resource immediately. It supports two sharing modes: Exclusive (only one thread can hold the resource, e.g., ReentrantLock) and Share (multiple threads can hold it simultaneously, e.g., Semaphore, CountDownLatch).

Custom synchronizers only need to implement the state‑access methods ( getState(), setState(), compareAndSetState()) and the appropriate acquisition/release hooks:

isHeldExclusively()
tryAcquire(int)

/ tryRelease(int) for exclusive mode tryAcquireShared(int) / tryReleaseShared(int) for shared mode

For example, the acquire(int arg) method (exclusive mode) works as follows:

public final void acquire(int arg) {
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

The flow is:

Attempt to acquire the resource directly via tryAcquire.

If it fails, enqueue the thread at the tail of the wait queue with addWaiter.

Enter acquireQueued to park the thread until it is unparked.

After successful acquisition, perform a self‑interrupt to preserve the interrupt status.

Similarly, the release(int arg) method releases the resource and wakes the next waiting thread:

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

In shared mode, acquireShared(int) and releaseShared(int) follow analogous logic, with the return value of tryAcquireShared indicating success, partial success, or failure, and doReleaseShared handling propagation to subsequent waiting threads.

The article also presents a simple application: a non‑reentrant Mutex built on AQS. The Mutex defines its own inner Sync class that implements tryAcquire and tryRelease, while the outer class exposes lock and unlock operations.

Overall, the piece demystifies AQS by breaking down its core framework, detailing the essential methods, and illustrating how custom synchronizers like Mutex can be constructed using this powerful concurrency primitive.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSynchronizationmultithreadingLockAQS
Qunar Tech Salon
Written by

Qunar Tech Salon

Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.