AQS的isHeldExclusively()方法
这段话描述了 AQS 中一个比较特殊的方法 isHeldExclusively(),它的作用通常容易被初学者忽视,因为它不像 tryAcquire 或 tryRelease 那样直接参与抢锁和释放锁的核心流程。
我们拆解来解释:
1. isHeldExclusively() 方法的作用
从字面意思看:“是否被独占持有?”
这个方法的作用是:判断当前线程(调用这个方法的线程)是不是目前持有这把独占锁的线程。
- 如果是,返回
true。 - 如果不是(比如锁在别人手里,或者根本没锁),返回
false。
它本质上是在问:“现在的锁主人是不是我?”
2. 为什么说“只有用到 Condition 才需要去实现它”?
这是因为 AQS 的 Condition(条件变量)机制 强依赖于这个判断。
什么是 Condition?
Condition 就像是 Java Object 的 wait() / notify() 的升级版。 比如你用 ReentrantLock 时,可以调用 newCondition() 创建一个等待队列。
lock.lock();
try {
while (条件不满足) {
condition.await(); // 释放锁,挂起,等待被唤醒
}
// 干活...
} finally {
lock.unlock();
}为什么 Condition 需要 isHeldExclusively()?
当你调用 condition.await() 时,AQS 内部会执行以下逻辑:
- 我得先释放锁(因为
await意味着我要放弃锁去睡一会)。 - 我要保存当前锁的状态(比如我是重入锁,重入了 3 次,我得记下来,等会被唤醒时我要恢复这 3 次重入)。
关键点来了: AQS 怎么敢随便释放锁?它必须先确认:“喂,正在操作 Condition 的这个线程,你真的持有锁吗?”
如果不检查,随便来个路人甲线程没拿锁就调 await(),AQS 尝试释放锁时就会乱套(释放了别人的锁,或者释放了根本不存在的锁)。
所以,AbstractQueuedSynchronizer.ConditionObject 在执行 await()、signal() 时,内部会强制调用 isHeldExclusively() 来进行检查:
- 如果
isHeldExclusively()返回false(你没拿锁),AQS 直接抛出IllegalMonitorStateException(非法监视器状态异常)。
这和 synchronized 块外面调用 wait() 会报错是一样的道理。
3. 如果我不用 Condition,还要实现它吗?
通常不需要。
如果你写的同步器(比如一个简单的不可重入互斥锁)不支持 Condition(即你不提供 newCondition() 方法),那么 AQS 内部除了 Condition 逻辑外,其他地方几乎不调用 isHeldExclusively()。
ReentrantLock实现了它,因为它支持 Condition。ThreadPoolExecutor中的Worker(继承自 AQS 实现的一个简易锁)也实现了它,主要用于判断线程是否空闲/中断。
总结
- 方法含义:判断当前线程是否是独占锁的持有者。
- 核心用途:主要用于 Condition(条件对象) 的逻辑检查。AQS 要保证只有持有锁的人才能调用
await()或signal()。 - 开发指导:
- 如果你要构建的锁支持
Condition,你必须重写这个方法。 - 如果你不需要
Condition功能,通常可以忽略这个方法。
- 如果你要构建的锁支持