AQS即AbstractQueuedSynchronizer,是Java并发包中构建锁和同步器的核心框架,其内部维护的state变量是一个volatile修饰的整型值,不同的同步工具通过操作这个变量实现各自的同步逻辑。Semaphore和CountDownLatch都采用了AQS的共享锁模式,二者的功能差异本质上是对state变量的定义和操作方式不同。

AQS共享锁与state变量的基础逻辑
AQS的共享锁模式下,多个线程可以同时获取锁,核心的判断逻辑围绕state变量展开。共享锁的获取和释放会分别调用tryAcquireShared和tryReleaseShared方法,这两个方法的具体实现由基于AQS的同步工具类自定义,而state变量就是这两个方法操作的核心对象。
当线程尝试获取共享锁时,会调用tryAcquireShared方法,方法的返回值决定了获取结果:返回负数表示获取失败,返回0表示获取成功但没有剩余资源,返回正数表示获取成功且还有剩余资源可以供其他线程获取。当线程释放共享锁时,会调用tryReleaseShared方法,返回true表示释放成功,可能会唤醒后续等待的线程。
Semaphore中state变量的作用
Semaphore的中文含义是信号量,它的作用是控制同时访问特定资源的线程数量,其底层就是通过AQS的共享锁实现的,state变量在这里表示可用的许可证数量。
Semaphore的初始化与state赋值
创建Semaphore对象时,需要传入初始的许可证数量,这个数量会直接赋值给AQS的state变量。比如我们创建一个有3个许可证的Semaphore:
import java.util.concurrent.Semaphore;
public class SemaphoreDemo {
public static void main(String[] args) {
// 初始化3个许可证,此时AQS的state值为3
Semaphore semaphore = new Semaphore(3);
}
}
获取许可证时的state操作
当线程调用acquire方法获取许可证时,Semaphore的tryAcquireShared方法会尝试将state值减1。如果减1后的结果大于等于0,说明还有可用许可证,获取成功;如果结果小于0,说明没有可用许可证,当前线程会被加入AQS的等待队列中阻塞。
下面是简化后的获取逻辑代码示例:
// Semaphore内部Sync类的tryAcquireShared简化实现
protected int tryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
// 如果剩余数量小于0,或者CAS更新state成功,返回结果
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
释放许可证时的state操作
当线程调用release方法释放许可证时,Semaphore的tryReleaseShared方法会将state值加1,然后唤醒等待队列中阻塞的线程尝试获取许可证。
简化后的释放逻辑代码示例:
// Semaphore内部Sync类的tryReleaseShared简化实现
protected boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // 溢出处理
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}
CountDownLatch中state变量的作用
CountDownLatch的作用是让一个或多个线程等待其他线程完成操作后再继续执行,它同样基于AQS的共享锁实现,state变量在这里表示需要等待的任务数量。
CountDownLatch的初始化与state赋值
创建CountDownLatch对象时,需要传入一个计数值,这个计数值会直接赋值给AQS的state变量。比如我们创建一个计数值为5的CountDownLatch:
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) {
// 初始化计数值为5,此时AQS的state值为5
CountDownLatch latch = new CountDownLatch(5);
}
}
await方法对应的state操作
当线程调用await方法时,CountDownLatch的tryAcquireShared方法会检查state的值。如果state等于0,说明所有任务都已完成,返回1表示获取成功;如果state不等于0,返回-1表示获取失败,当前线程会被加入AQS等待队列阻塞。
简化后的await逻辑代码示例:
// CountDownLatch内部Sync类的tryAcquireShared简化实现
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
countDown方法对应的state操作
当线程调用countDown方法时,CountDownLatch的tryReleaseShared方法会将state值减1。如果减1后state等于0,说明所有任务都已完成,返回true唤醒等待队列中阻塞的线程;如果减1后state仍大于0,返回false。
简化后的countDown逻辑代码示例:
// CountDownLatch内部Sync类的tryReleaseShared简化实现
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c - 1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
二者的state变量使用差异对比
虽然Semaphore和CountDownLatch都基于AQS共享锁实现,但state变量的使用逻辑有明显差异,具体对比如下:
| 对比维度 | Semaphore | CountDownLatch |
|---|---|---|
| state变量含义 | 可用许可证数量 | 待完成的任务数量 |
| 获取锁时state变化 | state减1,大于等于0则获取成功 | state不变,等于0则获取成功 |
| 释放锁时state变化 | state加1,唤醒等待线程 | state减1,减到0时唤醒等待线程 |
| state是否可重复增长 | 是,释放许可证会增长 | 否,只能递减到0 |
总结
通过state变量的逻辑可以清晰区分Semaphore和CountDownLatch的底层实现:Semaphore的state是可用资源数,获取时减少、释放时增加,支持多个线程同时获取资源;CountDownLatch的state是剩余任务数,只有递减到0时才能让等待线程继续执行,且state只会递减不会增长。理解state变量的作用,不仅能掌握这两个工具类的底层原理,也能更好地体会AQS框架的扩展性设计思路。
AQSstate_变量SemaphoreCountDownLatch共享锁修改时间:2026-06-28 19:51:34