1、概述
任意一个Java对象都拥有一组监视器方法(定义在java.lang.Object上),主要包括wait()、wait(long timeout)、notify()以及notifyAll()方法,与synchronised同步关键字配合,可以实现等待/通知模式。
Condition接口也提供了类似Object的监视器方法,与Lock配合,也可以实现等待/通知模式。
主要区别:Object只有一个等待队列,Condition允许多个等待队列。
2、原理分析
ConditionObject是Condtion的实现类,也是AbstractQueuedSynchronizer的内部类。即Condition实现的是同步器的内部类,因此每个Condition的实例都能访问同步器方法。
Object的监视器模型,一个对象有一个同步队列和一个等待队列;
而同步器拥有一个同步队列和多个等待队列。
1)等待
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();// 将当前线程进入等待队列
int 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);
}
调用await()方法,会使当前线程进入等待队列,并释放锁,线程状态变为等待状态。
从队列的角度看,相当于将同步队列的首节点移动到了Condition的等待队列中。
2)通知
public final void signal() {
// 判断当前线程是否获取了锁
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
首先检查当前线程是否获取了锁,获取锁之后,则调用同步器的enq(Node node) 方法,将等待队列的首节点(等待队列中等待时间最长的点)线程安全地移动到同步队列中,并使用LockSupport唤醒节点中的线程。
唤醒之后,将从await()方法的while循环中退出,进而调用同步器的acquireQueued()方法,加入到获取同步状态的竞争中。
Condition的signalAll()方法,相当于等待队列中的每个节点执行一次signal()方法,效果就是将等待队列中的所有节点全部移到同步队列中,并唤醒每个节点的线程。
3、LockSupport工具类
LockSupport定义一组公共静态方法,如park()、unpark()等,提供最基本的线程阻塞和唤醒功能。