Java自定义计数锁基于AQS共享模式实现,通过重写tryAcquireShared(检查state是否为0)和tryReleaseShared(CAS递减state并唤醒等待线程)来控制同步,state表示剩余计数,0为放行临界点。

Java 中的自定义计数锁(如类似 CountDownLatch 或可复用的计数器锁)通常基于 AQS 的共享模式实现,核心在于重写 tryAcquireShared 和 tryReleaseShared 方法,并合理维护一个共享状态值(如剩余计数)。AQS 共享模式允许多个线程同时获取锁(只要条件满足),非常适合“等待某个计数值归零才放行”的场景。
共享状态设计:用 state 表示剩余计数
AQS 内部的 state 字段天然适合作为计数器。初始化时设为正整数(如 3),每调用一次释放操作就原子减 1;获取操作则判断是否已到 0。注意:state = 0 是“允许通行”的临界点,不是“锁被占用”的标志——这与独占锁语义相反。
- 构造时通过
setState(count)初始化计数值 - 不支持负数计数(除非你主动扩展逻辑),
state < 0通常视为已触发完成态 - 所有状态变更必须使用 AQS 提供的 CAS 方法(如
compareAndSetState),保证线程安全
实现 tryAcquireShared:阻塞式等待计数归零
该方法返回值决定线程是否能立即获取共享锁:返回 ≥ 0 表示获取成功(可继续执行),返回负数(如 -1)表示需入队等待。对计数锁而言,“获取成功”意味着当前计数已为 0。
- 典型逻辑:读取当前
state,若为 0 则返回 1(或 0,AQS 对非负值一视同仁);否则返回 -1 进入同步队列等待 - 无需修改 state,只是观察状态 —— 获取操作本身不改变计数,只响应结果
- 注意避免伪唤醒:即使被唤醒也要重新检查 state,所以通常配合循环 +
getState()使用(AQS 框架已内置此逻辑)
实现 tryReleaseShared:原子递减并唤醒等待者
每次“倒计时”(如 countDown())调用此方法,目标是将 state 减 1,并在减到 0 时唤醒所有因未达标而阻塞的线程。
立即学习“Java免费学习笔记(深入)”;
- 使用无限循环 + CAS 实现无锁更新:
for (;;) { int current = getState(); if (current == 0) return true; int next = current - 1; if (compareAndSetState(current, next)) { return next == 0; } } - 返回
true表示本次释放可能触发唤醒(即 state 变为 0),AQS 会自动遍历同步队列,对所有共享节点调用doAcquireShared中的获取逻辑 - 即使多个线程同时
countDown(),CAS 保证只有一个是真正将 state 从 1→0 的,它负责唤醒,其余返回 false 不触发传播
可选增强:支持重复使用与中断感知
标准 CountDownLatch 不可重用,但你可以扩展为可重置的计数锁(如 CyclicBarrier 风格):
- 增加
reset(int newCount)方法:仅当当前 state == 0 时,用 CAS 设置新值;否则抛异常或忽略 - 若需响应中断,在 acquire 逻辑中调用
acquireSharedInterruptibly而非acquireShared,AQS 会自动处理InterruptedException - 调试时可重写
toString()返回"CountingLatch[state=" + getState() + "]",便于监控
不复杂但容易忽略:共享模式下线程获取的是“许可”而非“独占权”,因此多个线程可以同时从 acquireShared 返回并继续执行,这正是计数锁“门闩打开后大家一起过”的行为本质。


















