Java自定义锁最规范方式是继承AQS,重写tryAcquire/tryRelease实现独占逻辑,state管理状态,配合acquire/release封装lock/unlock,支持Condition需重写isHeldExclusively。

Java 中自定义锁最常用、最规范的方式是继承 AbstractQueuedSynchronizer(AQS),通过重写其核心模板方法来定义锁的获取与释放逻辑。AQS 本身不实现任何锁语义,而是提供统一的同步状态管理(state)、FIFO 等待队列和线程阻塞/唤醒机制,把“怎么判是否能抢到”“怎么更新状态”这些关键逻辑交给子类决定。
重写 tryAcquire 和 tryRelease(独占模式)
这是实现可重入独占锁(如 ReentrantLock)最核心的两个方法:
-
tryAcquire(int arg):由
acquire()调用,需原子判断并尝试获取锁。返回true表示成功(例如 state 从 0 变为 1,或当前线程已持有锁则 state+1);返回false则 AQS 自动将当前线程封装为 Node 加入同步队列并挂起。 -
tryRelease(int arg):由
release()调用,负责安全地释放锁。通常将state减去对应值,仅当state == 0时才真正释放成功(返回true),否则只是可重入计数减一(返回false)。
注意:这两个方法必须是线程安全的,推荐使用 compareAndSetState 或 getState/setState 配合 volatile 语义操作 state,不可直接修改。
实现 isHeldExclusively(用于 Condition 支持)
如果锁要支持 Condition(比如调用 newCondition()),就必须重写该方法,返回当前线程是否独占持有锁。AQS 的 ConditionObject 内部会用它来校验 signal 前的持有权。典型实现是判断 getExclusiveOwnerThread() == Thread.currentThread()。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
配合模板方法封装对外接口
AQS 提供了 acquire(int)、release(int)、acquireInterruptibly(int) 等公共模板方法,子类不应重写它们,而应提供符合 JDK 锁规范的 API,例如:
- 定义
lock()方法:内部调用acquire(1); - 定义
unlock()方法:内部调用release(1); - 若支持可中断,提供
lockInterruptibly():调用acquireInterruptibly(1); - 若支持超时,提供
tryLock(long, TimeUnit):调用tryAcquireNanos(1, nanos)。
这些方法都基于 AQS 已实现的健壮流程(排队、阻塞、中断响应、超时取消),你只需专注语义逻辑。
可选:支持共享模式(如读写锁中的读锁)
若需实现共享锁(多个线程可同时获取),还需重写 tryAcquireShared(int)(返回负数表示失败,0 表示成功但不唤醒后继,正数表示成功且可传播唤醒)和 tryReleaseShared(int)(无条件返回 true 表示可唤醒后继)。不过大多数自定义锁是独占式,共享模式多见于 ReentrantReadWriteLock.ReadLock 这类复合场景。
不复杂但容易忽略的是:所有状态变更必须围绕 state 字段展开,且不能在 tryAcquire 等方法中抛出异常(除非是 RuntimeException,AQS 不捕获检查异常),否则会破坏队列一致性。写好之后,配合 java.util.concurrent.locks.Lock 接口包装,就是一个标准、可组合、线程安全的锁实现。

















