Unlocking Java’s AQS: A Deep Dive into AbstractQueuedSynchronizer and Concurrency Primitives
This article explores the origins of Java's JUC package, explains the core concepts of AbstractQueuedSynchronizer—including template methods, exclusive and shared acquisition, CLH queues, CAS, and LockSupport—and demonstrates how locks, conditions, and synchronization mechanisms are implemented and used in real-world Java concurrency.
1. Origin of JUC
The synchronized keyword was originally implemented in JDK using heavyweight locks written in C++. Dissatisfied with its performance, Doug Lea created the JUC package to improve concurrency, focusing on AbstractQueuedSynchronizer (AQS) .
2. AQS Prerequisite Knowledge
2.1 Template Method
AbstractQueuedSynchronizeris an abstract class that follows the Template Method pattern; subclasses must implement specific methods.
Template Method Definition: An abstract class defines the skeleton of an algorithm, allowing subclasses to override specific steps while the overall flow remains unchanged.
public abstract class SendCustom {
public abstract void to();
public abstract void from();
public void date() { System.out.println(new Date()); }
public abstract void send();
public void sendMessage() {
to();
from();
date();
send();
}
}2.2 LockSupport
LockSupportprovides static methods to block and unblock threads. Common methods include park, parkNanos, parkUntil, and unpark. The metaphor is that a thread is a car; park stops it, unpark starts it.
2.3 CAS
Compare‑And‑Swap (CAS) is a CPU‑level atomic operation that provides lock‑free synchronization. It relies on the Unsafe class for hardware‑level compare‑and‑set.
3. Important AQS Methods
3.1 Exclusive Acquisition
The method acquire attempts to obtain the lock; if tryAcquire fails, the thread is added to the queue and may block.
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
} tryAcquiremust be implemented by subclasses (e.g., ReentrantLock) to handle fairness, re‑entrancy, and state checks.
3.1.1 acquire
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}3.1.2 acquireInterruptibly
Similar to acquire but responds to thread interruption.
public final void acquireInterruptibly(int arg) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}3.1.3 tryAcquireNanos
Attempts acquisition with a timeout, throwing InterruptedException if interrupted.
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout);
}3.2 Shared Acquisition
Shared mode is used by constructs such as CountDownLatch and Semaphore. The method acquireShared follows a similar pattern but works with shared state.
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}3.3 Release
Exclusive release invokes tryRelease and, if successful, wakes the successor.
public final boolean release(long arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}3.4 Shared Release
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}4. AQS Internals
4.1 CLH Queue
The CLH (Craig, Landin, Hagersten) queue is a FIFO linked list that provides fair, scalable spin‑lock behavior. Each thread enqueues a Node at the tail using CAS.
static final class Node {
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
volatile Node prev;
volatile Node next;
volatile Thread thread;
volatile int waitStatus;
// waitStatus values: CANCELLED=1, SIGNAL=-1, CONDITION=-2, PROPAGATE=-3, INITIAL=0
}4.2 Wait Status
The waitStatus field encodes node state: CANCELLED (1), SIGNAL (-1), CONDITION (-2), PROPAGATE (-3), and INITIAL (0).
4.3 Fair vs. Non‑Fair Locks
Fair locks respect queue order; non‑fair locks may allow barging, generally offering higher throughput.
4.4 Lock/Unlock Flow
When a thread calls lock.lock(), it invokes acquire(1). If acquisition fails, the thread is enqueued and may park. Upon unlock(), release(1) is called, which may unpark the successor.
5. Specific Synchronizers
5.1 CountDownLatch
CountDownLatchuses AQS in shared mode; each countDown() releases one shared permit.
public void countDown() {
sync.releaseShared(1);
}5.2 Semaphore
Semaphore maintains a permit count. Acquisition attempts to decrement the count; release increments it, potentially waking multiple waiting threads via setHeadAndPropagate.
5.3 ReentrantReadWriteLock
The lock uses a single 32‑bit int state: the high 16 bits track shared (read) count, the low 16 bits track exclusive (write) count. Each read lock thread has a HoldCounter to record re‑entrancy.
6. Condition Objects
Each Condition maintains its own wait queue separate from AQS's synchronization queue. Nodes in a condition queue have waitStatus = CONDITION and are transferred to the sync queue when signaled.
6.1 await
Calling await() releases the lock, enqueues the thread on the condition queue, and parks the thread until it is signaled.
6.2 signal / signalAll
signal()moves the first waiting node to the sync queue; signalAll() transfers all waiting nodes.
private void doSignal() {
Node first = firstWaiter;
if (first != null)
transferForSignal(first);
}
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
for (Node s = first; s != null; s = s.nextWaiter) {
s.nextWaiter = null;
transferForSignal(s);
}
}6.3 Practical Guidance
Because a lock can have many condition queues, use signal() when only one waiting thread should proceed, and reserve signalAll() for cases where all waiters must be awakened.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
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.
