Java 基于 AQS 实现自定义锁

发布时间:2026/8/14 2:33:15
Java 基于 AQS 实现自定义锁 目录核心源码流程说明改造为【可重入锁】AQS 独占模式需要重写的方法面试高频问题AQSAbstractQueuedSynchronizer是 JUC 锁的底层核心内部维护state 状态CLH 双向阻塞队列。state0锁空闲state1锁被占用CLH 队列存放等待获取锁的线程。要点自定义内部类继承AbstractQueuedSynchronizer重写tryAcquire、tryRelease独占模式对外封装 lock、unlock 方法这是不可重入独占锁示例javaimport java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.TimeUnit; /** * 基于AQS实现自定义独占锁不可重入 */ public class MyAqsLock implements Lock { // AQS同步器内部类 private static final class Sync extends AbstractQueuedSynchronizer { /** * 尝试获取独占锁 * 返回true 获取成功false 获取失败线程进入CLH队列阻塞 */ Override protected boolean tryAcquire(int arg) { // CAS把state从0改为1代表抢占锁成功 if (compareAndSetState(0, 1)) { // 设置当前线程为持有锁的线程 setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } /** * 尝试释放独占锁 */ Override protected boolean tryRelease(int arg) { // state为0说明锁已经释放抛异常避免unlock多次 if (getState() 0) { throw new IllegalMonitorStateException(); } // 清空持有锁线程 setExclusiveOwnerThread(null); // state置0释放锁 setState(0); return true; } /** * 是否是当前线程持有锁 */ Override protected boolean isHeldExclusively() { return getExclusiveOwnerThread() Thread.currentThread(); } // 返回条件变量用于await/signal Condition newCondition() { return new ConditionObject(); } } private final Sync sync new Sync(); Override public void lock() { // 独占模式获取锁获取失败则入队阻塞 sync.acquire(1); } 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() { // 释放锁会唤醒CLH队列后继线程 sync.release(1); } Override public Condition newCondition() { return sync.newCondition(); } // 测试 public static void main(String[] args) { MyAqsLock lock new MyAqsLock(); Runnable task () - { lock.lock(); try { System.out.println(Thread.currentThread().getName() 获取锁执行业务); TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); System.out.println(Thread.currentThread().getName() 释放锁); } }; new Thread(task, 线程A).start(); new Thread(task, 线程B).start(); new Thread(task, 线程C).start(); } }核心源码流程说明sync.acquire(1)java// AQS内部逻辑 public final void acquire(int arg) { if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }①调用我们重写的tryAcquire抢锁②抢锁失败addWaiter把当前线程封装成 Node 加入 CLH 队列尾部③acquireQueued自旋阻塞循环尝试抢锁抢不到就 park 挂起线程。sync.release(1)javapublic final boolean release(int arg) { if (tryRelease(arg)) { Node h head; if (h ! null h.waitStatus ! 0) unparkSuccessor(h); //唤醒队列下一个等待线程 return true; } return false; }调用重写tryRelease修改 state释放成功调用unparkSuccessor唤醒队列里的后继线程。改造为【可重入锁】上面代码是不可重入同一个线程重复 lock 会阻塞自己。修改tryAcquirejavaOverride protected boolean tryAcquire(int arg) { int state getState(); if (state 0) { // 锁空闲CAS抢占 if (compareAndSetState(0, arg)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } } else if (getExclusiveOwnerThread() Thread.currentThread()) { // 当前线程已经持有锁重入state累加 setState(state arg); return true; } return false; } Override protected boolean tryRelease(int arg) { if (getExclusiveOwnerThread() ! Thread.currentThread()) { throw new IllegalMonitorStateException(); } int state getState() - arg; boolean free (state 0); if (free) { setExclusiveOwnerThread(null); } setState(state); return free; }AQS 独占模式需要重写的方法方法作用tryAcquire尝试获取独占锁tryRelease尝试释放独占锁isHeldExclusively判断是否当前线程持有锁Condition 必须实现共享锁需要重写tryAcquireShared、tryReleaseShared。面试高频问题AQS 队列是什么CLH 双向链表队列每个 Node 封装线程LockSupport.park()阻塞线程不是 synchronized 的对象监视器。state 的 volatile 作用保证多线程 state 可见性修改 state 必须用 CAS 保证原子性。acquireQueued 为什么是自旋入队后不会直接 park先循环尝试抢几次锁减少线程挂起唤醒开销。为什么自定义锁一般把 Sync 写成内部类AQS 只是同步器不对外暴露由 Lock 做门面封装。