ConditionObject是同步器AQS的内部类,因为Condition的操作需要获取相关联的锁,所以作为同步器的内部类也比较合理。每个Condition对象都包含着一个FIFO队列(等待队列),该队列是Condition对象实现等待/通知的关键。
与object唤醒、等待方法的区别
Object中的wait(),notify(),notifyAll()方法是和"同步锁"(synchronized关键字)捆绑使用的;而Condition是需要与"互斥锁"/"共享锁"捆绑使用的。
等待队列
FIFO,每个节点都包含了一个线程引用,该线程就是在Condition对象上等待的线程,如果一个线程调用了await()方法,该线程就会释放锁、构造成节点进入等待队列并进入等待状态。
在Object的监视器模型上,一个对象拥有一个同步队列和等待队列,而Lock(同步器)拥有一个同步队列和多个等待队列。
A12.pngawait()
使当前线程进入等待队列并释放锁,同时线程状态变为等待状态。
从队列的角度来看,相当于同步队列的首节点(获取了锁的节点)移动到Condition的等待队列中。
+ View code
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 添加至等待队列中
Node node = addConditionWaiter();
// 释放同步状态,释放锁
long savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
调用此方法的线程已经有锁,即是同步队列的首节点,该方法将会将当前线程构造节点并加入等待队列,然后释放同步状态,唤醒同步队列中的后继节点,然后当前线程会进入等待状态。
当等待队列中的节点被唤醒,则唤醒节点的线程开始尝试获取同步状态,如果不是通过其他线程调用Condition.signal()方法唤醒,而是进行中断,将会抛出异常
通知
调用此方法的前置条件是当前线程必须获取了锁,可以看到signal()进行了isHeldExclusively()检查
调用Condition的signal(),将会唤醒等待队列的首节点,然后将其移到同步队列(使用enq确保移动到了同步队列)
被唤醒后的线程,将从await()方法中的while循环中退出,在同步队列中自旋
signalAll()则是相当于每个等待队列的线程都调用了一次signal()
网友评论