How to Build a Custom Java Lock with AbstractQueuedSynchronizer
This article explains how to extend AbstractQueuedSynchronizer to create a custom lock in Java, detailing the core AQS methods, the implementation of a PLock class, and the handling of exclusive and shared acquisition and release logic.
By extending AbstractQueuedSynchronizer (AQS), you can implement the core logic of a lock; AQS maintains an int state field to represent the lock state.
The AQS class provides several protected methods that subclasses must implement, such as tryAcquire, tryAcquireShared, tryRelease, tryReleaseShared, and isHeldExclusively.
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
// Exclusive mode: try to acquire the resource, return true on success, false on failure
protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); }
// Shared mode: try to acquire the resource, return negative on failure, zero on success with no remaining permits, positive on success with remaining permits
protected int tryAcquireShared(int arg) { throw new UnsupportedOperationException(); }
// Exclusive mode: try to release the resource, return true on success
protected boolean tryRelease(int arg) { throw new UnsupportedOperationException(); }
// Shared mode: try to release the resource, return true if subsequent nodes may be awakened
protected boolean tryReleaseShared(int arg) { throw new UnsupportedOperationException(); }
// Whether the current thread holds the lock exclusively (used by conditions)
protected boolean isHeldExclusively() { throw new UnsupportedOperationException(); }
}These methods are the core for acquiring and releasing locks. The following example shows a custom lock implementation using AQS.
public class PLock implements Lock {
private final Sync sync;
public PLock() {
sync = new Sync();
}
private class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1L;
public void lock() {
// compareAndSetState updates the state via CAS
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
@Override
protected boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
@Override
protected boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
@Override
protected boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
}
@Override
public void lock() { sync.lock(); }
@Override
public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); }
@Override
public boolean tryLock() { return sync.tryAcquire(1); }
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() { sync.release(1); }
@Override
public Condition newCondition() { return null; }
}Illustrations of the lock state transitions and queue management are shown below:
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.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.
