aqs 不支持分布式锁,仅适用于单机多线程环境;其独占/共享模式分别用于串行化写操作和读多写少场景;分布式锁需依赖 redis/zookeeper/etcd 等外部协调服务,aqs 仅可用于本地同步增强。

AQS 本身不直接支持分布式锁,它是 JVM 进程内(in-process)的同步框架,所有状态(如 state、队列节点、head/tail)都基于内存和线程共享,无法跨 JVM 或网络节点协调。因此,“利用 AQS 的独占与共享双模式编排分布式并发锁”这个说法存在根本性误解——AQS 不具备分布式能力,不能直接用于分布式场景。
独占模式与共享模式仅适用于单机多线程环境
它们的区别在于资源获取语义,而非部署形态:
-
独占模式:一次仅允许一个线程成功获取同步状态(如
ReentrantLock),适合保护临界区、串行化写操作; -
共享模式:允许多个线程同时获取(只要
tryAcquireShared()返回非负值),适合读多写少场景(如CountDownLatch、Semaphore、ReadWriteLock.ReadLock)。
二者都依赖本地 volatile int state 和双向同步队列(CLH 变种),所有操作在单 JVM 内原子、可见、有序——这与分布式所需的共识、网络通信、故障检测、租约续期等机制完全无关。
真正实现分布式锁必须脱离 AQS 直接依赖
常见可靠方案是组合外部协调服务 + 本地同步控制:
-
基于 Redis:用
SET key value NX PX timeout实现加锁,配合 Lua 脚本保证原子释放;本地可用 AQS 封装「锁获取成功后的临界区执行」逻辑(例如用ReentrantLock控制本地回调重入),但锁本身不由 AQS 管理; -
基于 ZooKeeper:利用临时顺序节点 + Watcher 实现公平锁;客户端在获取到最小序号节点后,可使用 AQS 的
Condition等机制组织本地等待/唤醒,但锁生命周期由 ZK 节点状态驱动; - 基于 Etcd(Raft):通过 lease + compare-and-swap 实现租约锁;本地可借助 AQS 构建「锁持有期间的资源访问控制器」,比如共享模式下限制最多 N 个线程并发访问缓存副本。
可复用 AQS 的地方:本地协同增强,而非分布式仲裁
在分布式锁客户端中,AQS 模式仍有实用价值,但角色明确:
- 用 独占模式 实现本地锁代理:例如封装 Redis 分布式锁客户端,内部用
ReentrantLock保护连接池、序列化器等共享资源,避免本地多线程争抢客户端元数据; - 用 共享模式 实现本地信号协调:例如多个线程协作等待某个远程条件(如 etcd 中某 key 出现),可用
CountDownLatch(AQS 共享实现)统一阻塞/释放,提升本地响应一致性; - 自定义同步器时复用 AQS 队列管理:若需实现「带超时自动降级的本地后备锁」,可继承
AbstractQueuedSynchronizer,在tryAcquire()中先尝试远程锁,失败则 fallback 到本地 CAS+队列,此时才真正用到 AQS 的双模式骨架。
总结:分清边界,各司其职
分布式锁的核心挑战是跨节点状态一致性和容错,这必须由分布式共识系统(Redis/ZooKeeper/Etcd)承担;AQS 是高性能、低开销的本地线程调度引擎,擅长把「已确认获得的权限」转化为安全、可控、可组合的线程行为。把 AQS 当作分布式锁的“实现基类”,就像用 ArrayList 实现数据库事务——方向错了。正确做法是:远程做仲裁,本地用 AQS 做执行治理。











