Mastering Java’s Unsafe park/unpark and AQS: Build Custom Locks with LockSupport

This article explains how Java’s Unsafe class provides low‑level park and unpark methods, how the LockSupport utility wraps them for easier use, and demonstrates building a simple exclusive lock with AbstractQueuedSynchronizer, covering state handling, blocking mechanisms, and thread‑queue management.

JavaEdge
JavaEdge
JavaEdge
Mastering Java’s Unsafe park/unpark and AQS: Build Custom Locks with LockSupport

Unsafe park and unpark

Unsafe defines two native methods that are the low‑level primitives for thread blocking:

public native void park(boolean isAbsolute, long time);
public native void unpark(Object thread);
park

blocks the current thread. The first boolean indicates whether the second argument is an absolute deadline ( true) or a relative timeout ( false). unpark wakes a thread that was previously blocked by park. The argument is the thread object to be unblocked.

Unsafe park/unpark diagram
Unsafe park/unpark diagram

LockSupport

The java.util.concurrent.locks package provides LockSupport as a convenient wrapper around the Unsafe primitives. Internally it calls Unsafe.park and Unsafe.unpark, so developers can avoid dealing with native signatures directly.

LockSupport usage diagram
LockSupport usage diagram

LockSupport also supports attaching a blocker object to a thread for debugging. It does this by using Unsafe.putObject to set the private Thread.parkBlocker field, which can later be read by diagnostic tools.

LockSupport blocker example
LockSupport blocker example

AbstractQueuedSynchronizer (AQS)

Most Java synchronizers—such as ReentrantLock, ReentrantReadWriteLock, Semaphore, and CountDownLatch —are built on the AbstractQueuedSynchronizer framework. The original design paper is available at http://gee.cs.oswego.edu/dl/papers/aqs.pdf.

Hand‑written exclusive lock using AQS

A minimal exclusive lock can be created by extending AQS with an inner Sync class and implementing the two core methods tryAcquire and tryRelease. The outer lock class then delegates lock() to sync.acquire(1) and unlock() to sync.release(1). The following example, called SimpleLock , demonstrates this pattern:

When a thread acquires the lock, all other threads are placed into the AQS wait queue.

When the owning thread releases the lock, the first queued thread is unblocked and attempts to acquire the lock.

SimpleLock result diagram
SimpleLock result diagram

The result shows that a few lines of AQS‑based code provide full mutex semantics.

AQS core principles

State value and atomic operations

private volatile int state;

protected final int getState() { return state; }

protected final void setState(int newState) { state = newState; }

protected final boolean compareAndSetState(int expect, int update) {
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

The state field represents the synchronizer's current condition. It is a volatile int so that reads see the latest value, and updates are performed atomically via CAS (compare‑and‑set) provided by Unsafe.compareAndSwapInt.

If state == 0, the synchronizer is in the released state and threads may acquire it.

If state != 0, the synchronizer is acquired . Subsequent threads join the wait queue. Re‑entrant synchronizers increment state to count recursive acquisitions.

Implementations may assign custom meanings to bits of state (e.g., separate read/write counters for a read‑write lock).

Blocking and unblocking

All blocking operations in AQS delegate to LockSupport . LockSupport.park puts the current thread into the wait set, and LockSupport.unpark wakes a specific thread. Because LockSupport itself uses Unsafe.park and Unsafe.unpark, the entire blocking mechanism ultimately relies on the Unsafe primitives.

Thread wait queue

AQS maintains a FIFO queue of Node objects. Each node stores a reference to the waiting thread, its wait status, and links to predecessor and successor nodes. The queue guarantees fair ordering for threads that cannot acquire the synchronizer immediately.

Source repository for the examples: https://github.com/Wasabi1234/Java-Concurrency-Programming-Tutorial

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.

javaconcurrencyAQSunsafeLockSupportCustomLock
JavaEdge
Written by

JavaEdge

First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.

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.